实现construct signature的正确方法是使用class
声明或表达式:
const NamedPerson: PersonConstructor = class {
constructor(public givenName: string, public familyName: string) { }
}
const person = new NamedPerson("John", "Doe");
console.log(person.familyName.toUpperCase()) // "DOE"
console.log(person instanceof NamedPerson); // true
在上面的class
表达式中,我使用了parameter properties来简化定义,但您不需要使用这个.
如果您想使用任意函数,则TypeScrip不会让您轻松做到这一点.ES5风格的构造函数在运行时工作(它们将属性赋给this
,而不是返回任何东西),但TypeScrip不想添加对此的支持,建议您"使用class
ES":参见microsoft/TypeScript#2310.从构造函数返回值也可以在运行时使用,但TypeScrip目前不允许您将类构造函数标记为生成this
类型以外的其他内容:有关功能请求,请参见microsoft/TypeScript#27594.而且TypeScrip并不能真正区分function
expressions(可以使用new
)和arrow functions(如果使用new
就会在运行时爆炸,即使您从未try 在其中使用this
),所以即使上面两个问题已经解决,您也需要注意您的函数不是错误类型的函数.
目前,要处理所有这些问题,需要使用某种具有type assertions的包装器函数来 suppress 编译器警告,并需要一个实现来使箭头函数可用.也许是这样的:
function toConstructor<A extends any[], R extends object>(
fn: (...args: A) => R): new (...args: A) => R {
return class {
constructor(...args: any) {
return fn(...args);
}
} as any;
}
然后你会像这样使用它
const NamedPerson: PersonConstructor =
toConstructor((givenName: string, familyName: string) => {
return { givenName, familyName }
});
const person = new NamedPerson("John", "Doe");
console.log(person.familyName.toUpperCase()) // "DOE"
console.log(person instanceof NamedPerson); // false
哦,是的,person instanceof NamedPerson
是false
,这很让人困惑.这是构造函数返回对象而不是赋值给this
的缺点之一;原型没有正确设置.因此,即使类型脚本使使用任意函数作为类构造函数变得很容易,它们也会导致奇怪的行为.
如果您希望将运行时和编译器中的问题降到最低,则应该将类用作类,将函数用作函数,而不是将它们混合在一起.如果你有一个函数,那么你只要把它当作一个函数来使用就会更好,根本不涉及the new
operator:
const namedPerson = (givenName: string, familyName: string): Person => {
return { givenName, familyName }
}
const person = namedPerson("John", "Doe");
console.log(person.familyName.toUpperCase()) // "DOE"
Playground link to code个