使用强类型的实现扩展通用接口

时间:2019-11-13 09:28:44

标签: typescript typescript-generics

我有一个Transformer界面:

interface Transformer<K> {
    type: string,
    apply<K>(data: K) : K
}

我想创建2个扩展Transformer的界面


interface NumberTransformer extends Transformer<number> {
    type: 'number',
    apply<number>(data: number) : number
}

interface StringTransformer extends Transformer<string> {
    type: 'string',
    apply<string>(data: string) : string
}

这会引发2个TS错误(TS6133) 'string'/'number' is declared but its value is never read,我不知道为什么

然后,在Transformer []列表中,我希望能够将type参数用作类型防护,例如

const a : DataTransformer<??>[] = [{
    type: 'number',
    apply: (n :number) => n * 10
},
{
    type: 'string',
    apply: (str :string) => str.substr(0,1)
}];

a.forEach(s => {
  if (s.type === 'string')
    //s.apply is string => string type
});

但是我不知道a的类型应该是什么? DataTransformer<any>吗?

1 个答案:

答案 0 :(得分:1)

type TransformerKeyType = {
  'number': number,
  'string': string,
}

interface DataTransformer<T extends keyof TransformerKeyType> {
    type: T,
    apply(data: TransformerKeyType[T]) : TransformerKeyType[T]
}

type NumberTransformer = DataTransformer<'number'>;
type StringTransformer = DataTransformer<'string'>;

const a : (DataTransformer<'number'> |  DataTransformer<'string'>)[] = [{
    type: 'number',
    apply: (n) => n * 10
},
{
    type: 'string',
    apply: (str) => str.substr(0,1)
}];

a.forEach(s => {
  if (s.type === 'string') {
    s // here properly we have DataTransformer<'string'>
  }
});

说明: TransformerKeyType是一种类型,它使我们在字符串和类型之间建立联系。这样我们就可以轻松地将字符串'number'映射为类型number

DataTransformer作为通用参数,它仅占用TransformerKeyType的键,因此只占用numberstring。并且该类型的正文自动通过说KK来设置正确的TransformerKeyType[T]。因此,请在T中键入给定属性TransformerKeyType

type NumberTransformer = DataTransformer<'number'>;是我们类型的实例。使用类型number

正确设置了应用功能

(DataTransformer<'number'> | DataTransformer<'string'>)[]表示我们有一个数组,其中包含或带数字的DataTransformer或带字符串的DataTransformer。这样很好用,因为您无需在apply函数中声明参数类型,并且可以将n => n * 10保留为数字的类型。