Jus*_*inM 4 typescript typescript-generics
我正在尝试编写一些克隆对象但更改深层属性的实用函数。
这是一个有点无用的版本的示例,它只是用可能属于不同类型的其他值替换对象的命名属性。该代码有效 - 它用新值替换了命名属性 - 但由于某种原因 TypeScript 无法确定所创建对象的类型并给出编译错误。为什么 TypeScript 不这样,我怎样才能让它工作?
我可以显式定义返回类型 - 但是对于该函数的版本来说,这会变得很尴尬,该版本会深度更改属性几个级别。
it('change type of input object', () => {
const cloneWith = <T extends Record<string, unknown>, A extends keyof T, V>(
i: T,
a: A,
value: V
) => ({
...i,
[a]: value,
});
const source = { name: 'bob', age: 90 };
const result = cloneWith(source, 'age', 'old!');
// This test passes
expect(result.age).to.equal('old!');
// But compile error - number and string have no overlap -
// on this line
if (result.age === 'old!') {
console.log('That person is old!');
}
});
Run Code Online (Sandbox Code Playgroud)
使用扩展语法创建的对象文字的推断类型并不总是理想的,特别是在涉及计算属性时。在这种情况下,T与索引签名相交{[x: string]: V},而Omit<T, A> & {[K in A]: V}更有意义(T没有属性和具有键和值A的单独对象的交集)。AT
我不知道如果没有显式返回类型,您将如何解决这个问题,但如果您添加返回类型,至少会推断出正确的类型。也许您可以对函数的其他版本执行类似的操作。
const cloneWith = <T, A extends keyof T, V>(
i: T,
a: A,
value: V
): Omit<T, A> & {[K in A]: V} => ({
...i,
[a]: value,
});
const source = { name: 'bob', age: 90 };
const result = cloneWith(source, 'age', 'old!');
type TestSource = typeof source.age // number
type TestResult = typeof result.age // string
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
910 次 |
| 最近记录: |