[英]TypeScript: Infer type of <this> in Object extension method
[英]Infer type of object of classes
构建一个表单配置构建器,想要动态推断类型,这里是最小的复制代码
interface Meta {
optional: boolean
}
class Base<Type = any> {
readonly _type!: Type
baseMeta: Meta
constructor() {
this.baseMeta = {
optional: false,
}
}
optional() {
this.baseMeta.optional = true
return this;
}
}
class FieldText extends Base<string> {
}
class FieldNumber extends Base<number> {
}
class Field {
static text() {
return new FieldText();
}
static number() {
return new FieldNumber();
}
}
const fields = {
fieldText: Field.text(),
fieldNumber: Field.number(),
fieldTextOptional: Field.text().optional(),
fieldNumberOptional: Field.number().optional(),
}
给定上面的代码,我想实现以下类型之一,不管是哪一个
type ExpectedType = {
fieldText: string;
fieldNumber: number;
fieldTextOptional: number | undefined;
fieldNumberOptional: number | undefined;
}
也不错
type ExpectedTypeWithOptionalKeys = {
fieldText: string;
fieldNumber: number;
fieldTextOptional?: number;
fieldNumberOptional?: number;
}
我已经开始推断类型,但无法弄清楚为什么不考虑可选属性
type ExtractFieldType<O, T> = O extends true ? T | undefined : T;
type SchemaType<T extends Record<string, Base>> = {
[Property in keyof T]: ExtractFieldType<T[Property]['baseMeta']['optional'], T[Property]['_type']>;
};
type Schema = SchemaType<typeof fields>;
type Schema
导致:
type Schema = {
fieldText: string;
fieldNumber: number;
fieldTextOptional: string;
fieldNumberOptional: number;
}
这个O extends true? T | undefined: T
O extends true? T | undefined: T
O extends true? T | undefined: T
总是返回 T,不考虑 optional 的实际值
在对@kelly为可选 function 提供值的答案进行了一番摸索之后,这是最终结果:
optional<T extends boolean>(value?: T): Base<Type, T> {
const optional = typeof value === 'boolean' ? value : true;
this.baseMeta.optional = optional as Optional;
return this as unknown as Base<Type, T>;
}
首先你不能有一个默认值,然后 Typescript 会生气:
Type 'boolean' is not assignable to type 'T'.
'boolean' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'boolean'.(2322)
因此,我们只需将 value 设为optional
,然后 rest 就像 Kelly 解释的那样工作
除了return this as unknown as Base<Type, T>;
如果您删除as unknown
部分,则会收到以下错误:
Conversion of type 'this' to type 'Base<Type, T>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
Type 'Base<Type, Optional>' is not comparable to type 'Base<Type, T>'.
Type 'Optional' is not comparable to type 'T'.
'Optional' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'boolean'.(2352)
这是Typescript Playground中的最终工作
Meta
中的optional
类型始终为boolean
。 您需要将值存储在泛型中以供以后使用:
interface Meta<Optional extends boolean> {
optional: Optional;
}
class Base<Type = any, Optional extends boolean = false> {
readonly _type!: Type
baseMeta: Meta<Optional>
constructor() {
this.baseMeta = {
optional: false as Optional,
}
}
optional(): Base<Type, true> {
this.baseMeta.optional = true as Optional; // needs unsafe assert, or alternatively //@ts-ignore
return this as Base<Type, true>;
}
}
然后,当您使用optional
更改它时,欺骗 TypeScript 相信您正在返回Base<Type, true>
。
你只需要改变它。 您的原始解决方案现在有效。
解决评论中的后续问题:
optional<T extends boolean = true>(value: T = true): Base<Type, T> {
this.baseMeta.optional = value as Optional;
return this as Base<Type, T>;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.