Typescript 为什么使用“时会丢失第二个泛型类型信息?”;推断;?
因此,我有一个抽象基类,它接收Typescript 为什么使用“时会丢失第二个泛型类型信息?”;推断;?,typescript,generics,Typescript,Generics,因此,我有一个抽象基类,它接收ValueType的值,并有一个函数,可以将其转换为TransformedType。这可以通过两种泛型来解决: 抽象类基类{ 公共摘要transformValue:(值:ValueType)=>TransformedType; } 现在我有两个类从Base扩展而来,一个用于ValueType字符串,另一个用于数字: 接口字符串转换{ someValue:字符串; } 类DerivedString扩展了基{ 公共转换值=(值:字符串):StringTransform
ValueType
的值,并有一个函数,可以将其转换为TransformedType
。这可以通过两种泛型来解决:
抽象类基类{
公共摘要transformValue:(值:ValueType)=>TransformedType;
}
现在我有两个类从Base
扩展而来,一个用于ValueType
字符串,另一个用于数字:
接口字符串转换{
someValue:字符串;
}
类DerivedString扩展了基{
公共转换值=(值:字符串):StringTransformed=>{
返回{someValue:value+“someValue”};
};
}
接口号已转换{
valuePlusPlus:数字;
}
类DerivedNumber扩展了基{
public transformValue=(值:number):NumberTransformed=>{
返回{valuePlusPlus:value+1};
};
}
之后,我创建了一个类型字段
,它需要一个通用类型T
,来自类型对象
:
类型字段={
[A in keyof T]:任何扩展基?基:从不
};
用法示例:
typemaintype={x:string;y:number};
常量字段:字段={
x:新衍生字符串(“测试”),
y:新衍生编号(2)
};
const transformed=fields.x.transformValue(“任意字符串”);
这里的问题是关于TransformedType
的类型信息丢失,因为它是未知的
:
与该类型不同,关于ValueType
的信息保持正确
问题:
在这里使用
推断正确吗?
为什么类型信息丢失
Base
的泛型参数中删除TransformedType
,并仅在transformValue
函数中使用它?(ValueType
需要在Base
中使用其他函数等,但TransformedType
仅用于transformValue
函数)any
cast我无法回避,这是我的实际问题
一般来说,我想在react中编写一个库来处理表单状态,所以它确实需要一种非常通用的方法。请记住,这个例子实际上非常简单,实际上要复杂得多 好的,对于第一个问题2:是的,您可以删除第二个类型参数,并将其默认为
unknown
,如果您这样定义它:
// default second parameter
abstract class Base<T, U = unknown> {
public abstract transformValue: (value: T) => U;
}
interface StringTransformed {
someValue: string;
}
class DerivedString extends Base<string> {
public transformValue = (value: string): StringTransformed => {
return { someValue: value + "someValue" };
};
}
interface NumberTransformed {
valuePlusPlus: number;
}
class DerivedNumber extends Base<number> {
public transformValue = (value: number): NumberTransformed => {
return { valuePlusPlus: value + 1 };
};
}
const asFields = <F extends Fields>(fields: F) => fields;
几乎一样。请注意,我给出了一个默认类型参数any
,因此Fields
本身意味着Fields助手函数手动指定T
,并让它推断出其余部分:
const asValueFields = <T>() => <F extends Fields<T>>(fields: F) => fields;
最后,让我们实现transformFields()
。对于给定的字段
类型,描述转换后的输出类型很有用。以下是我对它的定义:
type TransformedType<F extends Fields> = {
[K in keyof F]: F[K] extends Base<any, infer T> ? T : never
};
该实现与代码沙箱中的实现相同,其中一些是经过仔细放置的,以使编译器相信您所做的是正确的。基本上,我们断言Object.keys(fields)
将返回T
的键数组,fields[key]
是一个Base
,它接受T[K]
并输出TransformedType[K]
,而reduce()
累加器是一个TransformedType
唷!让我们使用它:
const transformedMainType = transformFields(fields, { x: "", y: 1 });
transformedMainType.x.someValue; // okay
transformedMainType.y.valuePlusPlus; // okay
看起来不错。请注意,您不必从以前开始使用helper函数“prep”字段。如果您有一个正确类型的对象文字,它也会正常工作:
const alsoWorks = transformFields(
{ x: new DerivedString(), y: new DerivedNumber() },
{ x: "", y: 1 }
);
alsoWorks.x.someValue; // okay
alsoWorks.y.valuePlusPlus; // okay
好吧,那太多了。希望这能给你一些指导。祝你好运
类型信息看起来不像一开始就不存在的那样“丢失”<代码>任何扩展…推断…
几乎不会对您有多大帮助,因为您正在分析任何
。为什么不干脆去掉字段的注释
并让常量字段={x:new-DerivedString(),y:new-DerivedNumber()}
?如果这不起作用,你能告诉我在哪里吗?祝你好运@我编辑了我的问题并添加了一个代码沙盒。希望这将有助于更好地理解我的问题。遗憾的是,我不能仅仅使用字段的注释,因为我希望一个通用的字段
作为函数的参数(请参见transformFields.ts
中的codesandbox)哇,这非常有帮助和详细!使用它已经在我的代码和作品像一个魅力,感谢很多打字大师!
const asValueFields = <T>() => <F extends Fields<T>>(fields: F) => fields;
const fieldsAlso = asValueFields<MainType>()({
x: new DerivedString(),
y: new DerivedNumber()
});
const badFieldsAlso = asValueFields<MainType>()({
x: new DerivedNumber(), // error! string is not number
y: new DerivedString() // error! number is not string
});
fieldsAlso.x.transformValue("anystring").someValue; // okay
type TransformedType<F extends Fields> = {
[K in keyof F]: F[K] extends Base<any, infer T> ? T : never
};
const transformFields = <T extends object, F extends Fields<T>>(
fields: F,
values: T
): TransformedType<F> => {
return (Object.keys(fields) as Array<keyof T>).reduce(
<K extends keyof T>(transformedObj: TransformedType<F>, key: K) => ({
...transformedObj,
[key]: (fields[key] as Base<T[K], TransformedType<F>[K]>).transformValue(
values[key]
)
}),
{} as TransformedType<F>
);
};
const transformedMainType = transformFields(fields, { x: "", y: 1 });
transformedMainType.x.someValue; // okay
transformedMainType.y.valuePlusPlus; // okay
const alsoWorks = transformFields(
{ x: new DerivedString(), y: new DerivedNumber() },
{ x: "", y: 1 }
);
alsoWorks.x.someValue; // okay
alsoWorks.y.valuePlusPlus; // okay