打字稿中的默认值和泛型

时间:2018-09-24 09:59:59

标签: typescript generics default-value

我想创建以下类:

class MyClass<T = {}> {
  constructor(private values: () => Promise<T> = () => Promise.resolve({})) {}
}

当然,编译器会抱怨,因为类型T是未知的,因此不可能为其分配空对象:

Type '() => Promise<{}>' is not assignable to type '() => Promise<T>'.

但是我每次使用默认值MyClass创建一个新的T对象时,都将默认方法赋予构造函数是很“肮脏的”。

您认为写这篇文章的最好方法是什么?

1 个答案:

答案 0 :(得分:1)

如您所指出的,将{}指定为任何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;}>

我们仍然使用类型断言来将默认值放入参数中,但是该签名不可见,并且如果{}不是该类型的有效默认值,则编译器将强制我们指定默认值。< / p>