gpt4 book ai didi

Typescript 将类缩小为有区别的联合

转载 作者:行者123 更新时间:2023-12-04 17:35:19 27 4
gpt4 key购买 nike

我很难将一个类的实例缩小到它的可区分联合。

我有以下受歧视的联盟:

interface ILoadableLoading<T> {
state: "Loading";
id: number;
}

interface ILoadableLoaded<T> {
state: "Loaded";
id: number;
item: T;
}

interface ILoadableErrored<T> {
state: "Error";
id: number;
error: string;
}

export type ILoadableDiscriminated<T> =
| ILoadableLoading<T>
| ILoadableLoaded<T>
| ILoadableErrored<T>;

type ILoadableState<T> = ILoadableDiscriminated<T>["state"];

还有下面的类:

class Loadable<T> {
state: ILoadableState<T> = "Loading";
id: number = 0;
item?: T | undefined;
error?: string | undefined;
}

现在我怎样才能将该类的实例缩小到其各自的 ILoadableDiscriminated<T> union 保持某种类型安全(不使用任何)?

例如我有以下创建方法,并希望返回已区分的联合:

unction createLoadable<T>(someState: boolean): ILoadableDiscriminated<T> {
var loadable = new Loadable<T>();

if (someState) {
loadable.state = "Error";
loadable.error = "Some Error";

// Would like to remove this cast, as it should narrow it out from state + defined error above
return loadable as ILoadableErrored<T>;
}

if (loadable.state === "Loading") {
// Would like to remove this cast, as it should narrow it from state;
return loadable as ILoadableLoading<T>;
}

if (loadable.state === "Loaded" && loadable.item) {
// Would like to remove this cast, as it should narrow it from state;
return loadable as ILoadableLoaded<T>;
}

throw new Error("Some Error");
}

sample 可在以下网址找到:https://codesandbox.io/embed/weathered-frog-bjuh0文件:src/DiscriminatedUnion.ts

最佳答案

问题是 Loadable<T> 之间没有关系并定义了保证该功能的接口(interface) createLoadable()在退回项目之前将每个属性设置为正确的状态。例如,Loadable<string>可以有这个值:

var loadable = new Loadable<string>();
loadable.state = "Error";
lodable.item = "Result text.";
return loadable;

以上不适合任何接口(interface),但有效Loadable实例。

我的方法如下:

简化界面,只有一个必须是通用的:

interface ILoadableLoading {
state: "Loading";
id: number;
}

interface ILoadableLoaded<T> {
state: "Loaded";
id: number;
item: T;
}

interface ILoadableErrored {
state: "Error";
id: number;
error: string;
}

export type ILoadableDiscriminated<T> =
| ILoadableLoading
| ILoadableLoaded<T>
| ILoadableErrored;

type ILoadableState<T> = ILoadableDiscriminated<T>["state"];

为每个接口(interface)创建单独的类,以确保创建的对象符合接口(interface)定义:

class LoadableLoading implements ILoadableLoading {
state: "Loading" = "Loading";
id: number = 0;
}
class LoadableLoaded<T> implements ILoadableLoaded<T> {
constructor(public item: T){}
state: "Loaded" = "Loaded";
id: number = 0;
}
class LoadableErrored implements ILoadableErrored {
constructor(public error: string){}
state: "Error" = "Error";
id: number = 0;
}

然后我们可以使用带重载的函数来说明意图:

function createLoadable<T>(someState: true, state: ILoadableState<T>, item?: T): ILoadableErrored;
function createLoadable<T>(someState: false, state: "Loading", item?: T): ILoadableLoading;
function createLoadable<T>(someState: false, state: "Loaded", item?: T): ILoadableLoaded<T>;
function createLoadable<T>(someState: boolean, state?: ILoadableState<T>, item?: T): ILoadableDiscriminated<T> {
if (someState) {
return new LoadableErrored("Some error");
}

if (state === "Loading") {
// Would like to remove this cast, as it hsould figure it out from state;
return new LoadableLoading();
}

if (state === "Loaded" && item) {
// Would like to remove this cast, as it hsould figure it out from state;
return new LoadableLoaded(item);
}

throw new Error("Some Error");
}

最后根据你输入的参数给createLoadable()函数,类型为返回类型,自动判别:

const lodableError = createLoadable<string>(true, "Loading");
console.log(lodableError.error);

const lodableLoading = createLoadable<string>(false, "Loading");
console.log("Loading");

const loadableLoaded = createLoadable<string>(false, "Loaded", "MyResponse");
console.log(loadableLoaded.item)

请注意,Typescript 编译器的参数重载状态意图,但您需要确保函数体中的代码执行您声明的内容。

关于Typescript 将类缩小为有区别的联合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56922296/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com