我在一家工廠作業;我最終需要添加自定義方法,但多虧了這個答案和這個答案,我們才能讓它按預期作業。
現在我需要通過一個選項來控制 id 的型別,我再一次如此接近,但我仍然缺少一些東西。
我需要id通過str選項來控制屬性true的型別:如果型別id必須是string,而如果false不提供,則型別id必須是number,但我得到string | number.
type Base = { save: () => Promise<boolean> }; // Base and BaseId must be kept separated for next steps ;)
type BaseId<B extends boolean> = { id: B extends true ? string : number };
type Options<B extends boolean> = { opt1?: boolean; opt2?: number; opt3?: string; str?: B };
type Factory<E> = new () => E;
function factory<B extends boolean, E extends Base & BaseId<B>>(name: string, options?: Options<B>): Factory<E>;
function factory<B extends boolean, E extends Base & BaseId<B>, M extends Record<string, <S extends M>(this: E & S) => unknown>>(
name: string, options: Options<B>, methods: M & Record<string, ((this: E & M) => void)>
): Factory<E & M>;
function factory<B extends boolean, E extends Base & BaseId<B>, M extends Record<string, <S extends M>(this: E & S) => unknown>>(
name: string, options?: Options<B>, methods?: M & Record<string, ((this: E & M) => void)>
): Factory<E> {
const ret = function (this: E) {};
Object.defineProperty(ret, "name", { value: name });
if(methods) Object.assign(ret.prototype, methods);
return ret as unknown as Factory<E>;
}
const T1 = factory("T1");
const t1 = new T1();
t1.id = "0"; // Error: string | number but number is expected
console.log(t1, t1.id);
const T2 = factory(
"T2", { str: true }, {
test: function (repeat = true) {
if (repeat) this.test(false);
return "test";
}
}
);
const t2 = new T2();
t2.id = "0"; // Ok: string
console.log(t2, t2.id, t2.test());
這里是一個操場進行試驗。
uj5u.com熱心網友回復:
您string|number在第一種情況下有,因為options未提供第二個引數。您需要更改上/最后一個多載簽名并擺脫options. 您需要提供多載簽名而不是options因為options是可選引數。您提供了帶有 optional 的簽名options,帶有 requiredoptions但您沒有沒有沒有簽名options。由于B泛型引數與options引數系結,因此您需要使用一些默認值而不是B.
考慮這個例子:
type Base = { save: () => Promise<boolean> }; // Base and BaseId must be kept separated for next steps ;)
type BaseId<B extends boolean> = { id: B extends true ? string : number };
type Options<B extends boolean> = { opt1?: boolean; opt2?: number; opt3?: string; str?: B };
type Factory<E> = new () => E;
function factory<E extends Base & BaseId<false>>(name: string): Factory<E>;
function factory<B extends boolean, E extends Base & BaseId<B>, M extends Record<string, <S extends M>(this: E & S) => unknown>>(
name: string, options: Options<B>, methods: M & Record<string, ((this: E & M) => void)>
): Factory<E & M>;
function factory<B extends boolean, E extends Base & BaseId<B>, M extends Record<string, <S extends M>(this: E & S) => unknown>>(
name: string, options?: Options<B>, methods?: M & Record<string, ((this: E & M) => void)>
): Factory<E> {
const ret = function (this: E) { };
Object.defineProperty(ret, "name", { value: name });
if (methods) Object.assign(ret.prototype, methods);
return ret as unknown as Factory<E>;
}
const T1 = factory("T1");
const t1 = new T1();
t1.id = "0"; // Error: string | number but number is expected
t1.id = 1; // Ok number
我已用作false默認型別的游樂場B
更新
boolean 是一個聯合 true | false
如果你不想接觸多載簽名,你可以檢查是否B是聯合。如果它是一個聯合 ( boolean) 則意味著它B不是推斷出來的,我們需要使用一些默認值:
// credits goes to https://stackoverflow.com/a/50375286
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
// credits goes to https://stackoverflow.com/questions/53953814/typescript-check-if-a-type-is-a-union
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true
type Base = { save: () => Promise<boolean> };
type BaseId<B extends boolean> = { id: IsUnion<B> extends true ? number : B extends true ? string : number }; // <------ CHANGE IS HERE
type Options<B extends boolean> = { opt1?: boolean; opt2?: number; opt3?: string; str?: B };
type Factory<E> = new () => E;
function factory<B extends boolean, E extends Base & BaseId<B>>(name: string, options?: Options<B>): Factory<E>;
function factory<B extends boolean, E extends Base & BaseId<B>, M extends Record<string, <S extends M>(this: E & S) => unknown>>(
name: string, options: Options<B>, methods: M & Record<string, ((this: E & M) => void)>
): Factory<E & M>;
function factory<B extends boolean, E extends Base & BaseId<B>, M extends Record<string, <S extends M>(this: E & S) => unknown>>(
name: string, options?: Options<B>, methods?: M & Record<string, ((this: E & M) => void)>
): Factory<E> {
const ret = function (this: E) { };
Object.defineProperty(ret, "name", { value: name });
if (methods) Object.assign(ret.prototype, methods);
return ret as unknown as Factory<E>;
}
const T1 = factory("T1");
const t1 = new T1();
t1.id = "0"; // Error: id should be number
操場
一般來說,既然id是必需的屬性而options不是,id不應該依賴options.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/382652.html
標籤:打字稿
