使用强类型实现扩展通用接口
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
的键,因此仅采用 number
或 string
。通过说 K
是 TransformerKeyType[T]
,类型的主体会自动设置正确的 K
。因此,在 TransformerKeyType
中键入给定的 属性 T
。
type NumberTransformer = DataTransformer<'number'>;
是我们类型的实例。它正在正确设置类型为 number
的应用函数
(DataTransformer<'number'> | DataTransformer<'string'>)[]
表示我们有一个数组,其中包含带数字的 DataTransformer 或带字符串的 DataTransformer。它工作得很好,因为你不需要在应用函数中声明参数类型,你可以离开 n => n * 10
,其中类型被称为数字。
我有一个 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
的键,因此仅采用 number
或 string
。通过说 K
是 TransformerKeyType[T]
,类型的主体会自动设置正确的 K
。因此,在 TransformerKeyType
中键入给定的 属性 T
。
type NumberTransformer = DataTransformer<'number'>;
是我们类型的实例。它正在正确设置类型为 number
(DataTransformer<'number'> | DataTransformer<'string'>)[]
表示我们有一个数组,其中包含带数字的 DataTransformer 或带字符串的 DataTransformer。它工作得很好,因为你不需要在应用函数中声明参数类型,你可以离开 n => n * 10
,其中类型被称为数字。