我这样声明了Typescript接口:
interface ProductFieldMapping {
name: string,
mapping: (p: Product) => string | number,
formatting: <T>(t: T) => T,
}
还有一个返回此类字段列表的函数,如下所示:
export const mappingFunctions = (host: string): ProductFieldMapping[] => {
const mappings = defaultFunctions(host)
return [
{
name: 'title',
mapping: mappings.productName,
formatting: (s: string) => s,
},
]
}
但是当我要分配格式此简单功能(s: string) => s
Type '(s: string) => string' is not assignable to type '<T>(t: T) =>
T'.
我想念什么?
可能的解决方法:
type MappingResult = | string | number
interface ProductFieldMapping<T> {
name: string,
mapping: (p: Product) => T,
formatting: (t: T) => T,
}
export const mappingFunctions = (host: string): ProductFieldMapping<MappingResult>[] => {
const mappings = defaultFunctions(host)
return [
{
name: 'title',
mapping: mappings.productName,
formatting: compose([limitSize(255), replaceNewLine(' ')]),
}]
}
答案 0 :(得分:1)
在调用函数时需要提供类型。
对于您的情况,应将string
替换为T
。
因为您只分配了函数,而不调用它。
formatting: <T>(s: T) => s,
然后在调用该函数时,然后为该函数指定一个类型。
formatting<string>("1") // it doesn't throw error
formatting<number>(1) // it doesn't throw error
编辑
我看到文档中有一章涉及Generic Classes。
VLAZ有相同的方法,但是文档使用类。
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericString = new GenericNumber<string>();
myGenericString.zeroValue = "0";
myGenericString.add = function(x, y) {
return x + y.toLocaleLowerCase(); // it works
};
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) {
return Math.round(y) // it works
};
答案 1 :(得分:1)
您可以使用ProductFieldMappings
使用discriminated union(also see here)来加强类型。
有区别的联合是您在多个类型上具有联合,但可以使用它们上的属性来缩小类型的范围。
interface ProductFieldMapping<T> {
name: keyof Product,
mapping: (p: Product) => T,
formatting: (t: T) => T,
}
interface StringFieldMapping extends ProductFieldMapping<string> {
type: "string";
}
interface NumberFieldMapping extends ProductFieldMapping<number> {
type: "number";
}
type Mapping = StringFieldMapping | NumberFieldMapping;
这使ProductFieldMapping
成为通用接口,其中mapping
和formatting
的结果绑定在一起,并且必须使用相同的格式。由于我们只有两种格式,因此我们为每种类型创建一种-StringFieldMapping
和NumberFieldMapping
。它们每个都有一个独特的type
,因此Mapping
现在是一个有区别的联合。
从这里您可以生成Mappings
的数组,您会知道它们使用正确的数据:
const numFormat = (n: number) => Math.round(n);
const strFormat = (s: string) => s.toLowerCase();
export const mappingFunctions = (host: string): Mapping[] => {
const mappings = defaultFunctions(host);
return [
{ // OK
name: 'title',
type: "string", // it's a string
mapping: mappings.productName, // produces string ✔
formatting: strFormat, // consumes string ✔
},
{ // OK
name: 'price',
type: "number", // it's a number
mapping: mappings.price, // produces number ✔
formatting: numFormat, // consumes number ✔
},
{ // ERROR
name: 'a',
type: "string", // it's a string
mapping: mappings.productName, // produces string ✔
formatting: numFormat, // consumes number ❌
},
{ // ERROR
name: 'b',
type: "number", // it's a number
mapping: mappings.price, // produces number ✔
formatting: strFormat, // consumes string ❌
},
{ // ERROR
name: 'c',
type: "string", // it's a string
mapping: (p: Product) => 42, // produces number ❌
formatting: strFormat, // consumes string ✔
},
{ // ERROR
name: 'd',
type: "number", // it's a number
mapping: (p: Product) => "hello", // produces string ❌
formatting: numFormat, // consumes number ✔
},
]
}