【发布时间】:2019-09-04 09:16:12
【问题描述】:
我有一个联合类型,它表示用户可以使用表单字段构造的一段数据。基本流程是用户选择他们想要制作的东西,然后我呈现正确的 UI,当他们编辑表单字段时,我更新存储的对象。进行中的对象表示为联合类型的部分化版本,具体取决于用户选择制作的事物的类型。有两种方式我想引用 Partial-ized 类型,但都有问题。
代码 sn-p 可以解释更多,但基本上,回调的签名和类型保护是我想引用进行中值的两种方式。在我想出的定义部分化联合类型的两种方案中,两个用例之一无法编译。
看起来变体一更正确和精确,所以我很惊讶它无法正确编译。我想尽可能避免强制转换,以使这段代码尽可能健壮,以便向联合类型添加更多成员。
export interface Key {
type: "key";
key: string;
}
export interface KeyValue {
type: "key-value";
key: string;
value: string;
}
export type Either = Key | KeyValue;
export type Common = Pick<Either, "type" | "key">;
export const Common = {
toString: ({ type, key }: Common): string => null as any,
fromString: (s: string): Common => null as any,
};
// USE CASE 1: This does not work when using variant one, below.
const callback: (v: PartialEither) => void = null as any;
callback(Common.fromString(""));
// USE CASE 2: This does not work when using variant two, below.
// This makes sense, since variant two's definition drops the relationship between `type`
// and the corresponding object shape, so type narrowing can't work.
const either: PartialEither = null as any;
if (either.type === "key-value") {
either.value;
}
// VARIANT ONE
// Comment this out and replace it with variant two to see the errors change, above.
// Using this intermediate type so I can still rely on 'type' as the discriminant property of
// the PartialEither type.
type _PartialEither<T extends Either> = Pick<T, "type" | "key"> & Partial<Omit<T, "type" | "key">>;
export type PartialKey = _PartialEither<Key>;
export type PartialKeyValue = _PartialEither<KeyValue>;
export type PartialEither = PartialKey | PartialKeyValue;
// VARIANT TWO
// Uncomment this out replace variant one with it to see the errors change, above.
// type PartialEither = Pick<Either, "type" | "key"> & Partial<Omit<Either, "type" | "key">>
【问题讨论】: