Typescript:实现联合类型

tri*_*ris 4 typescript

我知道在 TS 中实现 Union Types 是不可能的,这是绝对合理的。但我可能正在寻找类似的东西/其他:

type TypeA = { a: string, b?: string }
type TypeB = { a: string, c?: string }
type UnionType = TypeA | TypeB;
type IntersectionType = TypeA & TypeB;

// Error:
// A class can only implement an object type or intersection of object types with statically known members.(2422)
class UnionClass implements UnionType {
    checkUnionProperties() {
        let x: UnionType = { a: '' };
    }

    a = 'a';
}

//This is possible
class IntersectClass implements IntersectionType {
    checkUnionProperties() {
        let x: IntersectionType = { a: '' };
    }

    a = 'a';
}
Run Code Online (Sandbox Code Playgroud)

我希望能够实现一个类型/接口,它具有类型共有的所有属性仅在本例中a: string),但实际上并不是 TypeA 或 TypeB 的类。有我正在寻找的语言功能吗?

T.J*_*der 5

此评论中,jcalz指出了以下事实:Pick<T, keyof T>whenT是联合类型提供了一种仅具有公共部分的类型:

\n
type TypeA = { a: string; b?: string; };\ntype TypeB = { a: string; c?: string; };\ntype UnionType = TypeA | TypeB;\n\ntype Common<T> = Pick<T, keyof T>;\n\ntype X = Common<UnionType>;\n//   ^? \xe2\x88\x92 type X = { a: string; }\n
Run Code Online (Sandbox Code Playgroud)\n

游乐场链接(为了避免疑问,即使其他属性\xc2\xa0\xe2\x80\x94和在您的示例中\xc2\xa0\xe2\x80\x94 不是可选的,情况也是如此。)bc

\n

你可以implement得到结果:

\n
type TypeA = { a: string; b?: string; };\ntype TypeB = { a: string; c?: string; };\ntype UnionType = TypeA | TypeB;\n\ntype Common<T> = Pick<T, keyof T>;\n\nclass UnionClass implements Common<UnionType> {\n    checkUnionProperties() {\n        let x: UnionType = { a: \'\' };\n        console.log(x);\n    }\n\n    a = "a";\n}\n
Run Code Online (Sandbox Code Playgroud)\n

游乐场链接

\n

这是类中没有的示例a = "a";,因此该类没有正确实现接口\xc2\xa0\xe2\x80\x94,这确实是一个错误,正如您所希望的那样。

\n
\n

用户makeitmore human在评论中指出了这个问题,其中有来自qiu 的出色答案,如果和都有一个名称相同但类型不同的属性,则以不同的方式处理它。例如,如果您有in but in ,则上面的结果将产生带有 的类型。这可能是您想要的,但如果不是,qiu 的答案已经为您介绍了该类型(有关详细信息,请参阅答案),这将完全省略:TypeATypeBx: stringTypeAx: numberTypeBCommon<TypeA | TypeB>x: string | numberSharedPropertiesx

\n
// `OmitNever` and `SharedProperties` from: https://stackoverflow.com/a/68416189/157247\ntype OmitNever<T extends Record<string, unknown>> = {\n    [K in keyof T as T[K] extends never ? never : K]: T[K];\n};\ntype SharedProperties<A, B> = OmitNever<Pick<A & B, keyof A & keyof B>>;\n
Run Code Online (Sandbox Code Playgroud)\n

class可以这样使用它:

\n
class UnionClass implements SharedProperties<TypeA, TypeB> {\n    checkUnionProperties() {\n        let x: UnionType = { a: "" };\n        console.log(x);\n    }\n\n    a = "a";\n}\n
Run Code Online (Sandbox Code Playgroud)\n

游乐场链接

\n

TypeA它对和显示的没有影响TypeB,因为它们不具有相同名称但不同类型的属性(如x我上面的描述),但如果它们有\xc2\xa0\xe2\x80 就会有区别\x94Common<TypeA | TypeB>将包含xas string | number,但SharedProperties<TypeA, TypeB>完全忽略它。

\n