如何使用神奇的 TypeScript 或递归?

How to use magic TypeScript or recursion?

我有两个方法:

public prop<K extends keyof ResponseInvitation.RootObject>(key: K) {
    return this._has(key) ? this.user[key] : null;
  }

  private _has(prop: string): boolean {
    return this.user.hasOwnProperty(prop);
  }

我这样使用:

let prop = this.prop('profile'); // Return object 

热调用 this.prop 的链,以防返回的 属性 是对象:

 let prop = this.prop(this.prop('profile').organization);

上面的注释意味着我尝试通过名称 profile 获取 属性。它 returns 对象,其中我们有 属性 organization 作为字符串。

我想我需要这个:

private _has(prop: string): boolean {
    let prop = this.user.hasOwnProperty(prop);

    if (typeof prop == 'object') {
       return this._has(prop);
    }
}

关于我的问题,我尝试重写一个逻辑并得到了这个工作代码:

interface RootObject { 
  name: string;
  organization: Org; 
}

interface Org { 
  name: string;
}

class A { 

  public user: any;
  public last: string;

public prop<K extends keyof RootObject>(key: K) {
  let  prop = this._has(key) ? this.user[key] : null;

  if (key == this.last) { 
    return prop;
  }

  if (typeof prop == 'object') {
    let k = Object.keys(prop)[0] as K;
    this.user = prop;
    return this.prop(k);
  }

  }

  private _has(prop: string): boolean {
    return this.user.hasOwnProperty(prop);
  }

  public propString(properties: string) { 
    this.last = properties.split('.').slice(-1).pop();
  }

}

let b = {
  'organization': {
    'name': 'Oleg'
  }
};

let a = new A();
a.user = b;
a.propString('organization.name');
let d = a.prop('organization');
console.log(d);

我不太确定你在找什么,因为你遗漏了一堆 class 实现。对于您要实现的目标,我将为您提供更通用的可能解决方案:

type WrapIfObject<T> = T extends object ? ObjectWrapper<T> : T; 
class ObjectWrapper<T> {
  constructor(public object: T) { }
  prop<K extends keyof T>(k: K): WrapIfObject<T[K]>;
  prop<K extends keyof T>(k: K): T[K] | ObjectWrapper<T[K]> {
    const val = this.object[k];
    return (typeof val === "object") ? new ObjectWrapper(val) : val;
  }
}

上面是一个名为ObjectWrapper的class,它包装了一个你传入构造函数的对象。当您使用对象的键之一调用 prop() 方法时,如果 不是 对象,则 return 值将是 属性 值,或包装 属性 值的 ObjectWrapper。通过这种方式,您可以链式调用 prop() 直到获得非对象值。请注意,prop()WrapIfObject<T[K]> 的 return 类型是 conditional type 而不是联合,这让编译器能够以一种更容易的方式强类型化输出使用。

让我们看看它是如何工作的:

const val = {a: {b: "hey"}, c: "you"};
const valWrap = new ObjectWrapper(val);
console.log(valWrap.prop("a").prop("b").charAt(0)); // "h"
console.log(valWrap.prop("c").charAt(0)); // "y"

以上类型检查没有错误; TypeScript 知道 valWrap.prop("a").prop("b")stringvalWrap.prop("c")string。如果你做错了它会抱怨:

const oops = valWrap.prop("a").charAt(0); // error!
// Property 'charAt' does not exist on type 'ObjectWrapper<{ b: string; }>'.

并且由于 distributive 属性 条件类型,它会在正确的地方产生联合:

const x = new ObjectWrapper({a: Math.random() < 0.5 ? "string" : {b: 3}});
const y = x.prop("a") ; // string | ObjectWrapper<{b: number}>
const z = (typeof y === "string") ? y.length : y.prop("b"); // number
console.log(z); // 6 or 3

请注意 y 是如何被认为是 或者 一个 string 一个 ObjectWrapper<{b: number}> .

无论如何,希望你能用它来给你一个想法如何解决你的问题。祝你好运!