TypeScript type definition for an object property path [duplicate]

无人久伴 提交于 2021-02-07 04:27:11

问题


Is it possible to type an array of strings in such a way that the array can only be a valid property path in a given object? The type definition should work for all deeply nested objects.

Example:

const object1 = {
    someProperty: true
};
const object2 = {
    nestedObject: object1,
    anotherProperty: 2
};

type PropertyPath<Type extends object> = [keyof Type, ...Array<string>]; // <-- this needs to be improved

// ----------------------------------------------------------------

let propertyPath1: PropertyPath<typeof object1>;

propertyPath1 = ["someProperty"]; // works
propertyPath1 = ["doesntExist"]; // should not work

let propertyPath2: PropertyPath<typeof object2>;

propertyPath2 = ["nestedObject", "someProperty"]; // works
propertyPath2 = ["nestedObject", "doesntExist"]; // should not work
propertyPath2 = ["doesntExist"]; // should not work

Link to TypeScript playground


回答1:


In the answer to the question this duplicates you can use the recursive Paths<> or Leaves<> type aliases, depending on whether or not you want to support all paths that start at the root and end anywhere in the tree (Paths<>) or if you want to only support paths that start at the root and end at the leaves of the tree (Leaves<>):

type AllPathsObject2 = Paths<typeof object2>;
// type AllPathsObject2 = ["nestedObject"] | ["nestedObject", "someProperty"] | 
//  ["anotherProperty"]

type LeavesObject2 = Leaves<typeof object2>;
// type LeavesObject2 = ["nestedObject", "someProperty"] | ["anotherProperty"]

I'll assume it's Paths but you can change it to Leaves if that fits your use case. Here's the behavior you get, which matches what you asked for:

let propertyPath1: Paths<typeof object1>;
propertyPath1 = ["someProperty"]; // works
propertyPath1 = ["doesntExist"]; // error!
//               ~~~~~~~~~~~~~~

let propertyPath2: Paths<typeof object2>;
propertyPath2 = ["nestedObject", "someProperty"]; // works
propertyPath2 = ["nestedObject", "doesntExist"]; // error!
//                               ~~~~~~~~~~~~~
propertyPath2 = ["doesntExist"]; // error!
//               ~~~~~~~~~~~~~

Okay, hope that helps; good luck!

Link to code




回答2:


It's possible using arrow functions

const object1 = {
    someProperty: true
};
const object2 = {
    nestedObject: object1,
    anotherProperty: 2
};

type PropertyPath<Type extends object> = (x: Type) => any;

let propertyPath1: PropertyPath<typeof object1>;

propertyPath1 = (x) => x.someProperty; // works
propertyPath1 = (x) => x.doesntExist; // should not work

let propertyPath2: PropertyPath<typeof object2>;

propertyPath2 = (x) => x.nestedObject.someProperty; // works
propertyPath2 = (x) => x.nestedObject.doesntExist; // should not work
propertyPath2 = (x) => x.doesntExist; // should not work

Playground Link



来源:https://stackoverflow.com/questions/59455679/typescript-type-definition-for-an-object-property-path

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!