Есть лучший способ сделать это? Я пытаюсь написать статическую фабричную функцию, которая принимает два аргумента: общий объект и тип класса и возвращает новый экземпляр (или частичный) заданного типа класса. Я хочу проверить, что свойства универсального объекта не нарушают типы или имена общедоступных свойств класса.
Поскольку это статическая функция, я не могу определить новый тип возвращаемого значения в фабричном классе. Поэтому я пытаюсь полагаться на доступ к ['prototype'], как будто это перечисление. Это разумный метод? Также кажется, что мне нужно расширить тип чего-то, чтобы компилятор имел доступ к свойству «прототип». Мне интересно, можно ли это написать как-то лучше, сохраняя при этом функцию импорта статической...?
export class emptyClass {
//intentionally empty. Can we get rid of this somehow? If so, what would T extend?
}
export class Person {
public id:number;
public name:string;
}
export class ImportObject<A> {
public static ImportCastStatic<U,T extends typeof emptyClass>(
untypedObject:{[K in keyof T['prototype']]?:T['prototype'][K]},
targetType:T)
:T['prototype'] {
let typedObject:T['prototype'] = <T['prototype']>new targetType();
return (typedObject);
}
}
export class Main {
constructor() {
//This is how I want to call it.
let q = ImportObject.ImportCastStatic({name:"Alice",id:3}, Person);
}
}
Вот как я, вероятно, поступил бы:
// removing unused generic A from ImportObject<A>
export class ImportObject {
// removing unused generic U from ImportCastStatic<U, T>
// reinterpret T to be the instance type, not the constructor type
public static ImportCastStatic<T>(
untypedObject: Partial<T>, // Partial of T
targetType: new () => T) // zero-arg constructor of T objects
: T {
let typedObject = new targetType(); // no annotation/assertion required
return Object.assign(typedObject, untypedObject); // do something with untypedObject
}
}
Важным моментом здесь является то, что я изменил ваш T
, чтобы он ссылался на тип пример вместо типа конструктор. Учитывая T
, вы можете описать тип конструктора объектов с нулевым аргументом T
с помощью new
able функционального типа new()=>T
(или {new(): T}
). Вы могли бы оставить T
в качестве типа конструктора, но тогда для ссылки на тип экземпляра вам нужно было бы сделать T['prototype']
(что нормально) или использовать псевдоним типа встроенныйInstanceType<T>
(что может быть лучше)... это гораздо больше многословный и утомительный код, однако. Лучше обнажить T
несколько раз и один new()=>T
, чем один раз обнажить T
и InstanceType<T>
несколько раз.
Менее важные, но все же заслуживающие внимания:
Я удалил типы A
и U
, так как вы ничего не делали с ними в своем примере кода. Как правило, неиспользуемые общие параметры представляют собой плохая идея, и их следует избегать.
Я предполагаю, что вы хотите сделать что-то с untypedObject
, верно? Я объединил его свойства в построенный typedObject
через Object.assign()
.
Существует псевдоним типа встроенный, называемый Partial<T>
, который точно такой же, как {[K in keyof T]?: T[K]}
, поэтому использовал его вместо этого.
Если у вас есть T
в качестве типа экземпляра, вам не нужно аннотировать typedObject
как T
или утверждать, что new targetType()
— это T
. Компилятор выведет это из известного типа typedObject
в качестве функции-конструктора.
Хорошо, надеюсь, это поможет; удачи!
Вау - отличный ответ! Потрясающий трюк, позволяющий запускать new() в конструкторе... Мне интересно, вызывает ли это какое-либо снижение скорости, в отличие от перехода к ['prototype']? - но приятно знать, что оба в порядке. Одна проблема заключается в том, что то, что я на самом деле здесь делаю, вызывает статическую функцию для типа T... которую я не включил в свой первоначальный код. Так что это не решает мою конкретную проблему (потому что теперь у меня нет обработки typeof T), но дает мне хорошие рекомендации о том, как написать это чисто. Маркировка правильная. Спасибо!