打字稿中的默认值和泛型
Default value and generics in typescript
我想创建以下 class:
class MyClass<T = {}> {
constructor(private values: () => Promise<T> = () => Promise.resolve({})) {}
}
当然,编译器会报错,因为类型 T
是未知的,因此不可能给它分配一个空对象:
Type '() => Promise<{}>' is not assignable to type '() => Promise<T>'.
但我觉得每次我创建一个具有默认 T
值的新 MyClass
对象时将默认方法提供给构造函数相当“脏”。
您认为最好的写法是什么?
正如您所指出的,将 {}
指定为任何 T
的默认值是不安全的,因此编译器禁止它。
如果你想强制编译器接受默认值,你可以使用类型断言:
class MyClass<T = {}> {
constructor(private values: () => Promise<T> = (() => Promise.resolve({})) as any) {}
}
缺点是对于 {}
不是有效默认值的类型,您将获得无效默认值,编译器不会警告您。
一种不同的方法是使用条件类型,Tuples in rest parameters and spread expressions 创建一个构造函数签名,该签名根据 T
的实际类型而变化。
class MyClass<T = {}> {
constructor(... values: {} extends T ? [(() => Promise<T>)?]: [() => Promise<T>])
constructor(private values: () => Promise<T> = (() => Promise.resolve({})) as any) {}
}
new MyClass<{}>()
new MyClass<{a?: number}>() // ok {} would be default
new MyClass<{a: number}>() // error {} would not be valid
new MyClass(() => Promise.resolve({}))
new MyClass(() => Promise.resolve({ a: 0})) // ok MyClass<{a: number;}>
new MyClass<{a: number;}>(() => Promise.resolve({ a: 0})) // ok MyClass<{a: number;}>
我们仍然使用类型断言将默认值放入参数中,但该签名不可见,如果 {}
不是该类型的有效默认值,编译器将强制我们指定默认值.
我想创建以下 class:
class MyClass<T = {}> {
constructor(private values: () => Promise<T> = () => Promise.resolve({})) {}
}
当然,编译器会报错,因为类型 T
是未知的,因此不可能给它分配一个空对象:
Type '() => Promise<{}>' is not assignable to type '() => Promise<T>'.
但我觉得每次我创建一个具有默认 T
值的新 MyClass
对象时将默认方法提供给构造函数相当“脏”。
您认为最好的写法是什么?
正如您所指出的,将 {}
指定为任何 T
的默认值是不安全的,因此编译器禁止它。
如果你想强制编译器接受默认值,你可以使用类型断言:
class MyClass<T = {}> {
constructor(private values: () => Promise<T> = (() => Promise.resolve({})) as any) {}
}
缺点是对于 {}
不是有效默认值的类型,您将获得无效默认值,编译器不会警告您。
一种不同的方法是使用条件类型,Tuples in rest parameters and spread expressions 创建一个构造函数签名,该签名根据 T
的实际类型而变化。
class MyClass<T = {}> {
constructor(... values: {} extends T ? [(() => Promise<T>)?]: [() => Promise<T>])
constructor(private values: () => Promise<T> = (() => Promise.resolve({})) as any) {}
}
new MyClass<{}>()
new MyClass<{a?: number}>() // ok {} would be default
new MyClass<{a: number}>() // error {} would not be valid
new MyClass(() => Promise.resolve({}))
new MyClass(() => Promise.resolve({ a: 0})) // ok MyClass<{a: number;}>
new MyClass<{a: number;}>(() => Promise.resolve({ a: 0})) // ok MyClass<{a: number;}>
我们仍然使用类型断言将默认值放入参数中,但该签名不可见,如果 {}
不是该类型的有效默认值,编译器将强制我们指定默认值.