[英]Overloading union types in TypeScript
我想定义一个 function f
使得 arguments 和返回类型是联合类型,但它们是绑定的,即当你调用f(anInputType)
时,你会得到aCorrespondingOutputType
作为结果。 我尝试了以下方法,它似乎适用于 TypeScript 4.1.3。
class Input1 {
type1Input: string = "I am type 1!";
}
class Input2 {
type2Input: string = "I am type 2!";
}
interface Output1 {
type1Output: string;
}
interface Output2 {
type2Output: string;
}
export type Input = Input1 | Input2;
export type Output = Output1 | Output2;
function f(_input: Input1): Output1;
function f(_input: Input2): Output2;
function f(_input: Input): Output {
return null as any as Output;
}
const input = new Input2();
const output = f(input);
output.type2Output // Compiles because the compiler can figure out that output is of type Output2
然而,在(我的)现实生活中,输入应该是 WebGL 对象。 同样的事情,我用Input1
替换WebGLTexture
和用Input2
替换WebGLBuffer
,不能编译。
interface Output1 {
type1Output: string;
}
interface Output2 {
type2Output: string;
}
export type Output = Output1 | Output2;
function f(_input: WebGLTexture): Output1;
function f(_input: WebGLBuffer): Output2;
function f(_input: WebGLTexture | WebGLBuffer): Output {
return null as any as Output;
}
const canvas = document.createElement("canvas")!;
const gl = canvas.getContext("webgl")!;
const input = gl.createBuffer()!;
const output = f(input);
output.type2Output // Does not compile because the compiler thinks that output is of type Output1
我错过了什么吗?
我正在阅读这些 TypeScript 问题:
以及这些其他问题:
但令我困扰的是使用现有类型(即WebGL 对象)与自定义类的行为之间的差异。
它看起来很冗长,但有了它我可以摆脱一个单一的实现。 由于应用程序其他部分的组织方式,这对我来说有点失败。 某事,某处,会看起来很丑。 但现在这很好! 谢谢!
下面的真实代码。
export type WebGLResource =
{ texture: WebGLTexture } |
{ buffer: WebGLBuffer } |
{ program: WebGLProgram } |
{ renderbuffer: WebGLRenderbuffer } |
{ framebuffer: WebGLFramebuffer };
export type ResourceMeta = TextureMeta | BufferMeta | ProgramMeta | RenderbufferMeta | FramebufferMeta;
function getMeta(<...omitted params...> resource: { texture: WebGLTexture }, required: true): TextureMeta;
function getMeta(<...omitted params...> resource: { buffer: WebGLBuffer }, required: true): BufferMeta;
function getMeta(<...omitted params...> resource: { program: WebGLProgram }, required: true): ProgramMeta;
function getMeta(<...omitted params...> resource: { renderbuffer: WebGLRenderbuffer }, required: true): RenderbufferMeta;
function getMeta(<...omitted params...> resource: { framebuffer: WebGLFramebuffer }, required: true): FramebufferMeta;
function getMeta(<...omitted params...> resource: { texture: WebGLTexture }, required: false): TextureMeta | null;
function getMeta(<...omitted params...> resource: { texture: WebGLBuffer }, required: false): BufferMeta | null;
function getMeta(<...omitted params...> resource: { buffer: WebGLProgram }, required: false): ProgramMeta | null;
function getMeta(<...omitted params...> resource: { renderbuffer: WebGLRenderbuffer }, required: false): RenderbufferMeta | null;
function getMeta(<...omitted params...> resource: { framebuffer: WebGLFramebuffer }, required: false): FramebufferMeta | null;
function getMeta(<...omitted params...> resource: WebGLResource, required: boolean): ResourceMeta | null {
...
}
Typescript 是结构性的,不是标称的。 这意味着如果两种类型具有相同的形状,但名称不同,则它们被认为是相同的类型。 不幸的是, WebGLTexture
和WebGLBuffer
似乎具有相同的形状。
如果您在 VSCode 或 typescript 操场中的任何一种类型上 cmd+click(或 ctrl+click),您可以看到它们是如何声明的。 这产生了这两个声明:
interface WebGLTexture extends WebGLObject {}
interface WebGLBuffer extends WebGLObject {}
遗憾的是,这两种类型都被简单地声明为未更改的WebGLObject
。 Typescript 无法区分它们。 因此,当您尝试触发第二个 function 过载时,typescript 会注意到第一个过载匹配,并使用它。
很难从这个人为的代码中建议一个更好的解决方案,但您可能会在这里需要一种不同的方法。
也许您可以改为接受 object 的密钥,以明确您传入的内容? 这样不同的重载并具有不同的参数类型。
function f(_input: { texture: WebGLTexture }): Output1;
function f(_input: { buffer: WebGLBuffer }): Output2;
function f(_input: { texture?: WebGLTexture, buffer?: WebGLBuffer }): Output {
return null as any as Output;
}
const canvas = document.createElement("canvas")!;
const gl = canvas.getContext("webgl")!;
const buffer = gl.createBuffer()!;
const texture = gl.createTexture()!;
f({ texture }).type1Output; // works
f({ buffer }).type2Output; // works
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.