【发布时间】:2021-02-10 23:58:23
【问题描述】:
问题本身比这更复杂,但我会尽量用简单的方式解释。
我有一个对象(它可能是一个不同的对象,比如说汽车或用户或其他什么)。
const car = {
model: 'Model A',
specs: {
motor: {
turbo: true
}
}
};
然后我有一个从属性名称中获取值的函数。
interface Data<T, K extends keyof T> {
keynames: string[];
values: Array<T[K] | null>;
}
const getValues = <T, K extends keyof T>(keynames: string[], data: T): Data<T, K> => {
const values: Array<T[K] | null> = [];
keynames.forEach(keyname => {
const value: T[K] | undefined = getObjectValue(data, keyname);
if (typeof value === 'undefined') {
values.push(null);
} else {
values.push(value);
}
});
return {
keynames,
values
}
};
// This works with key.name syntax, specs.motor.turbo returns true for example
const getObjectValue = <T, K extends keyof T>(
object: T,
keyName: string
): T[K] | undefined => {
const keys = keyName.split('.');
if (keys.length === 1) {
if (typeof object === 'object') {
if (keys[0] in (object as T)) {
return (object as T)[keys[0] as K];
}
return undefined;
}
return undefined;
} else {
const [parentKey, ...restElements] = keys;
if (!object) return undefined;
return (getObjectValue(
(object as T)[parentKey as K],
restElements.join('.')
) as unknown) as T[K];
}
};
例如,当我编写一些测试时,问题就变成了:
// ...
const data = getValues(['model', 'specs.motor.turbo'], car);
assert.deepEqual(data, {
keynames: ['model', 'specs.motor.turbo'],
values: ['Model A', true],
});
// ...
data 是我所期望的,我的函数返回与预期相同的对象,但出现错误:
Type 'boolean' is not assignable to type 'string | { motor: { turbo: boolean; }; }'.ts(2322)
这很明显,因为我只是在函数中推断 T[K] 而不是嵌套属性的类型。
如何实现这一点,所以我的函数适用于返回类型string | { motor: { turbo: boolean; }; } | { turbo: boolean; } | boolean。或者也许有一种更简单的方法来返回嵌套的属性值。
【问题讨论】:
-
这个问题并不完全是 this one 的重复,但它取决于它,因为将对象路径表示为虚线字符串是先决条件。
-
现在我在玩它,使用像
Leaves或Paths这样的东西对编译器来说真的很困难,并且会导致巨大的性能问题;我想我会走另一条路……
标签: node.js typescript