带有省略类型的 TypeScript 中的函数链接
Function chaining in TypeScript with Omit types
假设我想在 TypeScript 中实现类型化函数链,但在这种情况下,调用函数会从 return 类型中删除该函数。例如:
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
interface Chainable {
execute: () => Promise<void>;
}
interface Chain1 extends Chainable {
chain1?: () => Omit<this, 'chain1'>;
}
interface Chain2 extends Chainable {
chain2?: () => Omit<this, 'chain2'>;
}
let chain: Chain1 & Chain2 = {
execute: () => null,
chain1: () => {
delete chain.chain1;
return chain;
},
chain2: () => {
delete chain.chain2;
return chain;
}
};
chain.chain1().chain2().execute(); // Using the function chain
当我调用 chain.chain1()
时,我会得到 Pick<Chain1 & Chain2, "execute" | "chain2"
作为 return 类型,这很好,因为它阻止我调用 chain1
两次。
但是,一旦我将它与 chain2
函数链接起来,return 类型就变成了 Pick<Chain1 & Chain2, "chain1" | "execute"
。这将允许我再次调用 chain1
,这是我试图阻止的。理想情况下,编译器会抱怨 Property 'chain1' does not exist on type
:
chain.chain1().chain2().chain1(); // I want this to return a compiler error :(
我这样做的方式正确吗?是否可以在 TypeScript 中逐步将多个 Omit 类型组合在一起,以便 return 类型连续省略属性?
我认为 this
的类型是在首次检查函数时确定的,之后的任何时候都不会重新评估。因此 chain2
的第二次调用的 this
仍然是原始的 this
而不是 chain1
的 return 类型。我不确定这是预期的行为还是错误,您可能需要检查 GitHub 是否存在类似问题。
一种解决方法是使用将绑定到 this
的泛型类型参数为任何给定函数捕获 this
。这将确保通过函数链的正确类型流。一个小问题是使用箭头函数无法进行输入,您需要使用常规函数并访问 this
:
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
interface Chainable {
execute: () => Promise<void>;
}
interface Chain1 extends Chainable {
chain1?: <T extends Chain1>(this: T) => Omit<T, 'chain1'>;
}
interface Chain2 extends Chainable {
chain2?: <T extends Chain2>(this: T) => Omit<T, 'chain2'>;
}
let chain: Chain1 & Chain2 = {
execute: () => null,
chain1: function () {
delete this.chain1;
return this;
},
chain2: function () {
delete this.chain2;
return this;
}
};
chain.chain1().chain2().execute(); // Using the function chain
chain.chain1().chain2().chain1().execute(); // error
假设我想在 TypeScript 中实现类型化函数链,但在这种情况下,调用函数会从 return 类型中删除该函数。例如:
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
interface Chainable {
execute: () => Promise<void>;
}
interface Chain1 extends Chainable {
chain1?: () => Omit<this, 'chain1'>;
}
interface Chain2 extends Chainable {
chain2?: () => Omit<this, 'chain2'>;
}
let chain: Chain1 & Chain2 = {
execute: () => null,
chain1: () => {
delete chain.chain1;
return chain;
},
chain2: () => {
delete chain.chain2;
return chain;
}
};
chain.chain1().chain2().execute(); // Using the function chain
当我调用 chain.chain1()
时,我会得到 Pick<Chain1 & Chain2, "execute" | "chain2"
作为 return 类型,这很好,因为它阻止我调用 chain1
两次。
但是,一旦我将它与 chain2
函数链接起来,return 类型就变成了 Pick<Chain1 & Chain2, "chain1" | "execute"
。这将允许我再次调用 chain1
,这是我试图阻止的。理想情况下,编译器会抱怨 Property 'chain1' does not exist on type
:
chain.chain1().chain2().chain1(); // I want this to return a compiler error :(
我这样做的方式正确吗?是否可以在 TypeScript 中逐步将多个 Omit 类型组合在一起,以便 return 类型连续省略属性?
我认为 this
的类型是在首次检查函数时确定的,之后的任何时候都不会重新评估。因此 chain2
的第二次调用的 this
仍然是原始的 this
而不是 chain1
的 return 类型。我不确定这是预期的行为还是错误,您可能需要检查 GitHub 是否存在类似问题。
一种解决方法是使用将绑定到 this
的泛型类型参数为任何给定函数捕获 this
。这将确保通过函数链的正确类型流。一个小问题是使用箭头函数无法进行输入,您需要使用常规函数并访问 this
:
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
interface Chainable {
execute: () => Promise<void>;
}
interface Chain1 extends Chainable {
chain1?: <T extends Chain1>(this: T) => Omit<T, 'chain1'>;
}
interface Chain2 extends Chainable {
chain2?: <T extends Chain2>(this: T) => Omit<T, 'chain2'>;
}
let chain: Chain1 & Chain2 = {
execute: () => null,
chain1: function () {
delete this.chain1;
return this;
},
chain2: function () {
delete this.chain2;
return this;
}
};
chain.chain1().chain2().execute(); // Using the function chain
chain.chain1().chain2().chain1().execute(); // error