另一种可能的方法:
正如其他答案所提到的,您无法避免在运行时执行某些操作;TypeScript 编译为 JavaScript,主要是通过简单地删除接口/类型定义、注释和断言。类型系统被擦除,MyInterface
在需要它的运行时代码中无处可寻。
因此,您将需要类似要保留在缩减对象中的键数组之类的东西:
const myTestKeys = ["test"] as const;
这本身是脆弱的,因为如果MyInterface
被修改,您的代码可能不会注意到。让您的代码注意到的一种可能方法是设置一些类型别名定义,如果myTestKeys
与 不匹配,则会导致编译器错误keyof MyInterface
:
// the following line will error if myTestKeys has entries not in keyof MyInterface:
type ExtraTestKeysWarning<T extends never =
Exclude<typeof myTestKeys[number], keyof MyInterface>> = void;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Type 'UNION_OF_EXTRA_KEY_NAMES_HERE' does not satisfy the constraint 'never'
// the following line will error if myTestKeys is missing entries from keyof MyInterface:
type MissingTestKeysWarning<T extends never =
Exclude<keyof MyInterface, typeof myTestKeys[number]>> = void;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Type 'UNION_OF_MISSING_KEY_NAMES_HERE' does not satisfy the constraint 'never'
这不是很漂亮,但是如果您更改MyInterface
,上面的一行或两行将给出一个错误,希望该错误具有足够的表现力,开发人员可以修改myTestKeys
。
有很多方法可以使这更通用,或者可能不那么侵入性,但几乎无论你做什么,你可以合理地期望 TypeScript 的最好结果是你的代码在面对接口的意外更改时会发出编译器警告;并不是说您的代码在运行时实际上会做不同的事情。
一旦你有了你关心的键,你就可以编写一个pick()
函数来从对象中提取这些属性:
function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K> {
return keys.reduce((o, k) => (o[k] = obj[k], o), {} as Pick<T, K>);
}
我们可以在您的test
对象上使用它来获取reduced
:
var test: MyTest = { test: "hello", newTest: "world" }
const reduced: MyInterface = pick(test, ...myTestKeys);
console.log(JSON.stringify(reduced)); // {"test": "hello"}
这样可行!
Playground 链接到代码