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

Extend generic interface with strongly typed implementations

我有一个 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> ?

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。通过说 KTransformerKeyType[T],类型的主体会自动设置正确的 K。因此,在 TransformerKeyType 中键入给定的 属性 T

type NumberTransformer = DataTransformer<'number'>; 是我们类型的实例。它正在正确设置类型为 number

的应用函数

(DataTransformer<'number'> | DataTransformer<'string'>)[] 表示我们有一个数组,其中包含带数字的 DataTransformer 或带字符串的 DataTransformer。它工作得很好,因为你不需要在应用函数中声明参数类型,你可以离开 n => n * 10 ,其中类型被称为数字。