问题描述
此问题建立在问题和已接受答案 in this link 的基础上。
我想编写一个表单生成器类,其中使用底层类型 T 来确定可以调用哪些函数。举个例子,假设这是我们想要一个表单的模型:
interface MyFormModel {
name: string;
options: number[];
isPrimary: boolean;
address: {
street: string;
houseNumber: number;
someArrayThatsRelevantToAddresses: string[];
}
}
我希望能够为属性 'isPrimary'
创建一个复选框,然后我希望 this
的返回值不包括用于创建复选框的方法,因为没有更多的布尔值剩下的属性可以调用“createCheckBox”。我使用第二个类型参数 K
跟踪哪些属性已经用完。每次使用来自 T 的键调用函数后,K 都会更新,以便我们跟踪哪些键已经用完。这是我的实现:
// T is the model for the form,K will accumulate props from T as we build the form
class FormBuilder<T,K extends Partial<T> = {}> {
buildCheckBox<NewKey extends BooleanKeysOf<T>>(): FormBuilder<T,AddProp<T,K,NewKey>> {
return this as any;
}
buildBlock<NewKey extends CompoundKeysOf<T>>(key: NewKey): FormBuilder<T,NewKey>> {
return this as any;
}
buildInput<NewKey extends StringOrNumberKeysOf<T>>(): FormBuilder<T,NewKey>> {
return this as any;
}
buildArray<NewKey extends ArrayKeysOf<T>>(): FormBuilder<T,NewKey>> {
return this as any;
}
finishForm(): K extends T ? FormForModel<T> : MissingProps<T,K> { // tells us which props are missing!
// use childforms to build a complete form
return 'hello' as any;
}
// Get a FormBuilder that accumulates props to build one of the object properties of the parent form
getChildBuilder<NewKey extends CompoundKeysOf<T>>(): FormBuilder<T[NewKey]> {
return new FormBuilder();
}
}
这使用了一些辅助类型:
/**
* Utility types
*/
// Get from Type T all of the keys that have values of type SomeType
type KeysOfType<T,SomeType> = { [K in keyof T]: T[K] extends SomeType ? K : never }[keyof T]
// Get all keys that are boolean,or string | number,or arrays,or other objects
type BooleanKeysOf<T> = KeysOfType<T,boolean>;
type StringOrNumberKeysOf<T> = KeysOfType<T,string | number>;
type ArrayKeysOf<T> = KeysOfType<T,any[]>;
type CompoundKeysOf<T> = Exclude<KeysOfType<T,object>,ArrayKeysOf<T>>; // get all props that have object types,except arrays
// a type representing the form we're building
type FormForModel<T> = { [K in keyof T]: {} } };
// Add to K another prop that's a part of T
type AddProp<T,K extends Partial<T>,NewKey extends keyof T> = K & { [S in NewKey]: T[S] };
// Which props are missing from K to fill out T?
type MissingProps<T,K extends Partial<T>> = Omit<T,keyof K>;
使用这种方法,可以很容易地将每个函数的类型参数限制为之前没有被调用过的键,直到调用签名变成 NewKey extends never
并且无法进行调用。
但是,当函数没有合法值可供调用时,我想从类型签名中完全删除它。我想像这样:
buildCheckBox<NewKey extends Exclude<BooleanKeysOf<T>,keyof K>>(): MaybeExcludeCheckBox<T,NewKey> {
return this as any;
}
type MaybeExcludeCheckBox<T,NewKey extends keyof T> = Exclude<keyof T,NewKey> extends never? Omit<FormBuilder<T,NewKey>>,'buildCheckBox'> : FormBuilder<T,NewKey>>
它的作用是检查是否有任何剩余的布尔属性,如果有则返回 FormBuilder 类型,如果没有,则省略 'buildCheckBox' 属性。但是,有时我想打开或关闭多个功能。每次调用函数时,是否有更简洁的方法来添加/删除多个属性?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)