[英]TypeScript generics: how to define type T which is structurally the same as other type S
I have a notion of a Step
, which requires value of type A
as an input and gives out a value of type B
.我有一个
Step
的概念,它需要类型A
值作为输入并给出类型B
的值。
class Step<A, B> {
constructor(private readonly f: (a: A) => B) { }
public run(a: A): B {
return this.f(a);
}
}
Now I would like to compose two steps, so I end up with something like this inside class Step
:现在我想编写两个步骤,所以我最终在
class Step
得到了这样的东西:
public andThen<C, D>(nextStep: Step<C, D>): Step<A, D> {
return new Step<A, D>((state: A) => {
const b: B = this.f(state);
return nextStep.run(b); // <---- compile error, B and C have no relation defined
});
}
What I would like to achieve is to somehow tell the type system that we can pass type B
to a function which expects type C
(structural typing should check that all fields in C
are present in B
), so that the line return nextStep.run(b)
works fine.我想要实现的是以某种方式告诉类型系统我们可以将类型
B
传递给一个需要类型C
的函数(结构类型应该检查C
中的所有字段是否都存在于B
),以便该行return nextStep.run(b)
工作正常。
Example:例子:
const stepA: Step<{}, {a: number, b: string}> = new Step((input: {}) => ({ a: 5, b: "five" }));
const stepB: Step<{a: number}, {c: number}> = new Step((input: {a: number}) => ({c: input.a + 5}));
const steps = stepA.andThen(stepB)
As you can see stepB
requires as an input {a: number}
, so it can be fed an output from stepA
which is {a: number, b: string}
.如您所见,
stepB
需要作为输入{a: number}
,因此它可以从stepA
获得输出,即{a: number, b: string}
。 But I cannot figure out how to define the relation in andThen
.但我不知道如何定义
andThen
的关系。 Any thoughts how this can be achieved?任何想法如何实现?
type SubType<T, WiderT> = T extends WiderT ? WiderT : never;
class Step<A, B> {
constructor(private readonly f: (a: A) => B) { }
public run(a: A): B {
return this.f(a);
}
public andThen<C, D>(nextStep: Step<SubType<B, C> | B, D>): Step<A, D> {
return new Step<A, D>((state: A) => {
const b = this.f(state);
return nextStep.run(b);
});
}
}
const stepAB: Step<{}, {a: number, b: string}> =
new Step((input) => ({ a: 5, b: "five" }));
const add5 = ({ a }: { a: number }) => ({ c: a + 5 });
const stepCD: Step<{ a: number }, { c: number }> = new Step(add5);
const stepAD = stepAB.andThen(stepCD);
The core point is SubType
type:核心点是
SubType
类型:
type SubType<T, WiderT> = T extends WiderT ? WiderT : never;
It says that if the type extends given type then its ok, but its not then never.它说如果类型扩展给定类型那么它可以,但它不是那么永远不会。 Pay attention how it is used:
注意它是如何使用的:
SubType<B, C> | B
So we are saying that if type B
extends C
, so B
is more specific type then C
then we allow on that, if not we don't by never
.所以我们说,如果类型
B
扩展C
,那么B
是比C
更具体的类型,那么我们允许这样做,如果不是,我们就never
。 Additionally we allow on B
itself (without union there was still compilation error)此外,我们允许
B
本身(没有联合,仍然存在编译错误)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.