如何在TypeScript中按引用传递属性以实现类型安全更新?
TypeScript类型安全的属性读写问题
通过名称读取对象属性的方式有很多种,但这些方式似乎都无法在不进行显式类型转换的情况下更新属性。
我们需要一个能安全读写属性值的类型安全函数,原始场景是编辑属性值,为简化说明,本文以给属性值追加空格为例。
读取正常,但更新报错的实现
1. 使用{ [k in K]: string }和keyof T
function appendSpace1< T extends { [k in K]: string }, K extends keyof T >(obj: T, path: K) { let x = obj[path]; // `x` is `T[K]` let y = x + " "; // `y` is `string` obj[path] = y; // Type 'string' is not assignable to type 'T[K]'.(2322) return x; }
2. 使用Record<K, string>和string
function appendSpace2< T extends Record<K, string>, K extends string >(obj: T, path: K) { let x = obj[path]; // `x` is `T[K]` let y = x + " "; // `y` is `string` obj[path] = y; // Type 'string' is not assignable to type 'T[K]'.(2322) return x; }
3. 使用Record<K, string>和KeysWithValsOfType<T, V>
type KeysWithValsOfType<T, V> = keyof { [P in keyof T as T[P] extends V ? P : never]: P; }; function appendSpace3< T extends { [k in K]: string }, K extends KeysWithValsOfType<T, string> >(obj: T, path: K) { let x = obj[path]; // `x` is `T[K]` let y = x + " "; // `y` is `string` obj[path] = y; // Type 'string' is not assignable to type 'T[K]'.(2322) return x; }
读写正常,但存在局限的实现
1. 使用类
使用类时该方案可行,但将代码转换为泛型类型时会失败:
type MyClass = { a: number; b: number ; c: string ; } function increment<T>(obj: T, key: { [K in keyof T]-?: number extends T[K] ? K : never }[keyof T] ) { obj[key]++; // fail } const test: MyClass = {a: 0, b: 1, c: "two"}; increment(test, "a"); increment(test, "b"); increment(test, "c"); // fail increment(test, "d"); // fail
2. 使用常量属性名
function appendSpace4< T extends { x: string }, K extends "x" >(obj: T, path: K) { let x = obj[path]; // `x` is `T[K]` let y = x + " "; // `y` is `string` obj[path] = y; // OK! return x; }
但该方案不支持参数化,一旦将x改为[k in K]或keyof T,obj[path] = y就会再次出现ts2322错误。
我似乎已经接近解决方案,但始终无法完全实现,为何更新操作的类型检查如此不同?
内容的提问来源于stack exchange,提问作者Marcel Waldvogel
相关产品推荐
相关产品推荐

