Typescript:Intellisense 自动完成 - 自定义函数作为深度嵌套对象 属性,从对象 属性 推断它的参数类型
Typescript: Intellisense autocomplete - custom function as deeply nested object property, that infers it's argument type from the object property
基本上我有这种类型
type X = {
a: {
b?: string;
c?: string;
d: {
e:{
f:{
g?: boolean
}
}
};
};
};
// and a helper
const as = <T,>(arg: T):T => arg;
而且我需要能够创建一个 X 形状的对象
其中所有嵌套级别上的所有属性都替换为:
as({
// autocomplete here with actual object property
// unless it's not an object
})
// like so
const x = as<X>({
a: as({
b: as("some string"),
d: as({
e: as({
f: as({
g: as(false)
})
})
})
})
})
我在一定程度上让它工作了,但是在超过 2 层的嵌套中,自动完成不再...自动完成
请参阅Typescript playground link以更好地理解问题。
所以...在来自 typescript 的 Discord 社区的人的帮助下,我让它工作了。
最终工作示例:
type IsObject<T> = T extends Array<any>
? false
: T extends Date
? false
: T extends object
? true
: false;
type BuiltInFn = "someFn";
type NullableUndefinedOrEmptyUnion = "nullable" | "undefined" | "emptyString";
type Primitive<T> = T extends string
? "string"
: T extends boolean
? "boolean"
: T extends number
? "number"
: never;
type NN<T> = NonNullable<T>;
type S<T, R = T> = IsObject<NN<T>> extends true
? {
[K in keyof T]?: IsObject<NN<T[K]>> extends false
? S<NN<T[K]>, R>
:
| (<XX extends S<NN<T[K]>, R>>(
value: XX | undefined,
root: R
) => boolean | void)
| (<XX extends S<NN<T[K]>, R>>(
value: <YY extends S<NN<T[K]>, R>>(value: YY, root: R) => boolean | void,
root: R
) => XX | void);
}
:
| (<XX extends NN<T>>(
value: Primitive<XX> extends never
? BuiltInFn | undefined
: Primitive<XX> | undefined,
root: R
) => XX | void)
| (<XX extends NN<T>>(
value: <YY extends NN<T>>(value: YY, root: R) => boolean | void,
root: R
) => XX | void);
function s<T>(s: S<T, T>): S<T, T> {
return s;
}
type A<T> = T extends (value: infer U, root: infer UU) => infer Z ? U : never;
function as<T>(arg: A<T>, ...opts: Array<BuiltInFn | NullableUndefinedOrEmptyUnion>): NN<T> {
return arg as any;
}
type X = {
a?: {
b?: string;
c?: number;
d: {
nested?: {
e: {
f: boolean;
};
g: {
x: number;
};
};
};
};
};
const x = s<X>({
a: as({
d: as({
nested: as({
e: as({
f: as("boolean"),
}),
}),
}),
b: as("string"),
}),
});
现在您可以使用可以接收 3 种类型作为参数的自定义函数:
- 对象 属性 本身(如果 prop === 对象)带有可选参数
- 一个带两个参数的匿名函数(对象 属性 本身和根对象)
- 如果参数不是对象,则为表示参数类型的字符串文字,或如上所述的匿名函数
而且...无论多深,所有内容都已输入
漂亮!
基本上我有这种类型
type X = {
a: {
b?: string;
c?: string;
d: {
e:{
f:{
g?: boolean
}
}
};
};
};
// and a helper
const as = <T,>(arg: T):T => arg;
而且我需要能够创建一个 X 形状的对象 其中所有嵌套级别上的所有属性都替换为:
as({
// autocomplete here with actual object property
// unless it's not an object
})
// like so
const x = as<X>({
a: as({
b: as("some string"),
d: as({
e: as({
f: as({
g: as(false)
})
})
})
})
})
我在一定程度上让它工作了,但是在超过 2 层的嵌套中,自动完成不再...自动完成
请参阅Typescript playground link以更好地理解问题。
所以...在来自 typescript 的 Discord 社区的人的帮助下,我让它工作了。
最终工作示例:
type IsObject<T> = T extends Array<any>
? false
: T extends Date
? false
: T extends object
? true
: false;
type BuiltInFn = "someFn";
type NullableUndefinedOrEmptyUnion = "nullable" | "undefined" | "emptyString";
type Primitive<T> = T extends string
? "string"
: T extends boolean
? "boolean"
: T extends number
? "number"
: never;
type NN<T> = NonNullable<T>;
type S<T, R = T> = IsObject<NN<T>> extends true
? {
[K in keyof T]?: IsObject<NN<T[K]>> extends false
? S<NN<T[K]>, R>
:
| (<XX extends S<NN<T[K]>, R>>(
value: XX | undefined,
root: R
) => boolean | void)
| (<XX extends S<NN<T[K]>, R>>(
value: <YY extends S<NN<T[K]>, R>>(value: YY, root: R) => boolean | void,
root: R
) => XX | void);
}
:
| (<XX extends NN<T>>(
value: Primitive<XX> extends never
? BuiltInFn | undefined
: Primitive<XX> | undefined,
root: R
) => XX | void)
| (<XX extends NN<T>>(
value: <YY extends NN<T>>(value: YY, root: R) => boolean | void,
root: R
) => XX | void);
function s<T>(s: S<T, T>): S<T, T> {
return s;
}
type A<T> = T extends (value: infer U, root: infer UU) => infer Z ? U : never;
function as<T>(arg: A<T>, ...opts: Array<BuiltInFn | NullableUndefinedOrEmptyUnion>): NN<T> {
return arg as any;
}
type X = {
a?: {
b?: string;
c?: number;
d: {
nested?: {
e: {
f: boolean;
};
g: {
x: number;
};
};
};
};
};
const x = s<X>({
a: as({
d: as({
nested: as({
e: as({
f: as("boolean"),
}),
}),
}),
b: as("string"),
}),
});
现在您可以使用可以接收 3 种类型作为参数的自定义函数:
- 对象 属性 本身(如果 prop === 对象)带有可选参数
- 一个带两个参数的匿名函数(对象 属性 本身和根对象)
- 如果参数不是对象,则为表示参数类型的字符串文字,或如上所述的匿名函数
而且...无论多深,所有内容都已输入
漂亮!