我想将一个对象限制为某种类型。但是我也希望能够使用“ as const”强制转换,以便可以将某些属性键入为类型文字。
请考虑以下对象:
user$ adb shell setprop persist.sys.timezone $"GMT-11.00"
我希望所有过滤器都遵循setprop: failed to set property 'persist.sys.timezone' to 'GMT-11.00'
接口的约束。但我希望打字稿将const COST_FILTER: IFilterBase = {
type: "cost",
displayName: "Cost",
fields: costFilterFields,
} as const
的类型视为IFilterBase
。可能吗?
答案 0 :(得分:4)
如果您明确指定类型,则打字稿将仅检查与接口的兼容性。评论中概述了一项建议,以支持该语言。
在这种情况发生之前,我们可以使用函数,元组和文字的推理规则:
[unknown] | unknown[]
的通用类型参数键入的位置,则将推断出元组。使用这些规则,我们可以创建一个递归映射类型,以将原始类型的属性映射到包含此类通用类型参数的新类型。我们没有为每个属性都分隔类型参数,一个参数将用于文字,一个参数将用于元组。这足以向编译器提示我们想要的东西。
type WithLiterals<T, L, LTuple> =
T extends string| number | boolean | null | undefined ? T & L :
{
[P in keyof T]:
WithLiterals<T[P], L, LTuple> & (T[P] extends Array<any> ? LTuple: unknown)
}
type DeepReadonly<T> = {
readonly [P in keyof T]: DeepReadonly<T[P]>
}
function asConst<TInterface>()
{
return function<
LTuple extends [unknown] | unknown[],
L extends string | boolean | number, T extends WithLiterals<TInterface, L, LTuple>>(o: T): DeepReadonly<T> {
return o as any
}
}
type IFilterBase = {
type: "cost" | "other",
displayName: string | undefined,
nr: number,
nrUnion: 1 | 2,
subObj : {
a: string;
}
arr: string[]
larr: ("A" | "B")[]
mixedarr: (number | string)[],
oArray: Array<{
a: string
}>
}
export const COST_FILTER = asConst<IFilterBase>()({
type: "other",
nr: 1,
nrUnion: 1,
displayName: "Cost",
subObj: {
a: "A"
},
arr: ["A", "B"],
larr: ["A"],
mixedarr: [1, ""],
oArray: [
{ a: ""}
]
})
键入为:
export const COST_FILTER : DeepReadonly<{
type: "other";
nr: 1;
nrUnion: 1;
displayName: "Cost";
subObj: {
a: "A";
};
arr: ["A", "B"];
larr: ["A"];
mixedarr: [1, ""];
oArray: [{
a: "";
}];
}>
答案 1 :(得分:0)
这可以通过使用虚拟验证功能来实现。
const validateType = <T> (obj:T) => undefined
剩下的就是使用类型和对象来调用它:
const COST_FILTER: IFilterBase = {
type: "cost",
displayName: "Cost",
fields: costFilterFields,
} as const
validateType<FilterBase>(COST_FILTER) // Will show an error if types don't match.