如何解决检查打字稿中的深点符号路径
Typescript挑战(来自更复杂代码的简化示例)...拆分深对象路径并键入检查原始字符串。
在打字稿中有可能吗?还是我必须编写运行时检查?
代码注释中的更多详细信息
interface Residence {
address: string;
year: number;
owner: {
name: string;
}
}
const house: Residence = {
address: 'Type street 1',year: 2010,owner: {
name: 'John Smith',},};
function getProp<T,K extends keyof T>(obj: T,key: K): T[K] {
return obj[key];
}
// The following lines work as expected,including giving type errors for non-existing keys:
getProp(house,'address');
getProp(house,'year');
// @ts-expect-error: As expected,since 'other' is not part of Residence
getProp(house,'other');
function deeper<T,P>(obj: T,path: P) {
// The logic here would be different,the point is splitting up the path
// to be able to check each part towards the deeper structure of the object
const firstProp = path.split('.')[0];
getProp(obj,firstProp);
}
// The problem is when combining flat keys with deep paths. Is the following possible,including type errors for the nonexisting paths?
deeper(house,'address');
deeper(house,'owner');
deeper(house,'owner.name'); // Should work since the deep path exists in the type
// @ts-expect-error: Property 'city' is not in Residence
deeper(house,'city');
// @ts-expect-error: Deep path owner.email is not in Residence
deeper(house,'owner.email');
解决方法
使用 TypeScript 4.1,您确实几乎可以使用模板文字类型来实现这一点
type NestedValueOf<Obj,Key extends string> =
Obj extends object ?
Key extends `${infer Parent}.${infer Leaf}` ?
Parent extends keyof Obj ?
NestedValueOf<Obj[Parent],Leaf>
: never
: Key extends keyof Obj ? Obj[Key] : never
: never
用法:
interface Residence {
address: string;
year: number;
owner: {
name: string;
}
}
const house: Residence = {
address: 'Type street 1',year: 2010,owner: {
name: 'John Smith',},}
function getProp<T,Key extends string>(obj: T,key: Key): NestedValueOf<T,Key> {
// TODO
}
getProp(house,'address') // string
getProp(house,'owner') // { name: string }
getProp(house,'owner.name') // string
getProp(house,'city') // never
此版本中未对 key
的 getProp
参数进行类型检查。 This answer 可能对此有所帮助
恐怕您不能完全做到这一点,您必须传递字符串数组,这是我们键入lodash get的范例。 (可能不是最漂亮的,但它可以工作,我们不再需要新的打字稿功能(例如新的字体保护程序和可选的链接)使用它
您要查找的结果是什么,如果需要检查对象是否来自联合,则应使用typeguards:https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards
import _ from 'lodash';
export interface TypedExtractor {
<T,K1 extends keyof T>(object: T,key1: K1): T[K1];
<T,K1 extends keyof T,K2 extends keyof T[K1]>(object: T,key1: K1,key2: K2): T[K1][K2];
<T,K2 extends keyof T[K1],K3 extends keyof T[K1][K2]>(object: T,key2: K2,key3: K3): T[K1][K2][K3];
<T,K3 extends keyof T[K1][K2],K4 extends keyof T[K1][K2][K3]>(
object: T,key3: K3,key4: K4,): T[K1][K2][K3][K4];
<
T,K4 extends keyof T[K1][K2][K3],K5 extends keyof T[K1][K2][K3][K4]
>(
object: T,key5: K5,): T[K1][K2][K3][K4][K5];
<
T,K5 extends keyof T[K1][K2][K3][K4],K6 extends keyof T[K1][K2][K3][K4][K5]
>(
object: T,key6: K6,): T[K1][K2][K3][K4][K5][K6];
<
T,K6 extends keyof T[K1][K2][K3][K4][K5],K7 extends keyof T[K1][K2][K3][K4][K5][K6]
>(
object: T,key7: K7,): T[K1][K2][K3][K4][K5][K6][K7];
<
T,K7 extends keyof T[K1][K2][K3][K4][K5][K6],K8 extends keyof T[K1][K2][K3][K4][K5][K6][K7]
>(
object: T,key8: K8,): T[K1][K2][K3][K4][K5][K6][K7][K8];
<
T,K8 extends keyof T[K1][K2][K3][K4][K5][K6][K7],K9 extends keyof T[K1][K2][K3][K4][K5][K6][K7][K8]
>(
object: T,key9: K9,): T[K1][K2][K3][K4][K5][K6][K7][K8][K9];
<
T,K9 extends keyof T[K1][K2][K3][K4][K5][K6][K7][K8],K10 extends keyof T[K1][K2][K3][K4][K5][K6][K7][K8][K9]
>(
object: T,key10: K10,): T[K1][K2][K3][K4][K5][K6][K7][K8][K9][K10];
}
export const _get: TypedExtractor = (object: any,...keys: (string | number)[]): string | number | object | undefined => {
return _.get(object,keys);
};
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。