如何使用神奇的 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")
是 string
而 valWrap.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}>
.
无论如何,希望你能用它来给你一个想法如何解决你的问题。祝你好运!
我有两个方法:
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")
是 string
而 valWrap.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}>
.
无论如何,希望你能用它来给你一个想法如何解决你的问题。祝你好运!