我正在尝试转换和过滤类Source
的实例的某些属性。为了重复执行尽可能少的代码,我决定从运行时可用的数据开始(我的键名放在数组中),然后从那里派生类型。
我希望对所有内容进行类型检查,以便在Source
中添加新属性时TS会警告我我忘记处理它。这就是我现在正在做的事情:
class Source {
data = "d";
meta = "m";
// if I un-comment this the compilation fails, that is what I want
// meta2 = "m2";
}
const keysTuple = <T extends Array<keyof Source>>(...args: T) => args;
const dataProps = keysTuple("data");
const metaProps = keysTuple("meta");
这就是我检查完整“覆盖率”的方式:
const _exhaustiveCheck: keyof Source extends
| typeof dataProps[number]
| typeof metaProps[number]
? boolean
: never = true;
仅仅为了对_exhaustiveCheck
进行类型检查而不得不引入never
变量似乎很奇怪,所以我想知道是否有更好的方法?
答案 0 :(得分:1)
您不必引入变量,至少不必在运行时引入。纯粹在类型级别,您可以执行以下操作:
type MutuallyExtends<T extends U, U extends V, V=T> = true;
type ExhaustiveCheck =
MutuallyExtends<keyof Source, typeof dataProps[number] | typeof metaProps[number]>;
但是我可能更喜欢在添加了额外属性的Source
类内部执行编译器错误的操作:
const keysTuple = <T extends Array<keyof any>>(...args: T) => args;
const dataProps = keysTuple("data");
const metaProps = keysTuple("meta");
type NoExtraKeys<T, K extends keyof T> = Record<Exclude<keyof T, K>, never>;
type DataMetaKeys = typeof dataProps[number] | typeof metaProps[number];
class Source implements NoExtraKeys<Source, DataMetaKeys>
{
data = "d";
meta = "m";
// if you un-comment this the compilation fails right here
//meta2 = "m2";
}
通过声明Source
实现了NoExtraKeys<Source, DataMetaKeys>
,诸如meta2
之类的任何额外键都将评估为Source implements {meta2: never}
之类的东西,这将失败。
希望有帮助。祝你好运!