与字符串文字类型的子类型匹配的手稿模式
问题描述:
export interface Action{
type: string;
}
export interface LoadTodos {
type: "LOAD_TODOS_ACTION"
}
export interface AddTodo {
type: "ADD_TODO_ACTION",
todo: Todo
}
export type KnownAction = LoadTodos | LoadTodosSuccess | AddTodo;
function isSomeType<T extends KnownAction>(x: any): x is T {
return x && typeof (x.type) === "LOAD_TODOS_ACTION";
}
let knownAction: actions.KnownAction = { type: "LOAD_TODOS_ACTION" };
if (isSomeType(knownAction)) {
let loadTodosAction = knownAction; // load Todos type
}
我在期待上面的行为。我想以通用的方式做到这一点,所以我不想重复如果,isSomeType函数中的else语句。基本上我想根据'type'属性将字符串文字类型转换为适当的类型。我的尝试是这样做的:与字符串文字类型的子类型匹配的手稿模式
function isSomeType<T extends Action>(x: any): x is T {
type p1 = T['type'];
return x && typeof (x.type) === p1;
}
但消息说''p1'只是指一种类型,但在这里用作一个变量。
有没有办法做到这一点?
答
不是一个明确的答案,但我不相信你可以。
FWIW推荐的方法可能是a switch on the discriminating member。
至于你的代码,你可能会失去跟踪类型信息丢失的地方。 typeof
运算符在这里不会有意义。 typeof
是一个运行时操作,即使您在运行时在代码中编写type: "LOAD_TODOS_ACTION"
typeof x.type
将返回string
,我认为这对您没有任何帮助。字符串文字类型意味着唯一可接受的可赋值是该字符串,而不是引入新类型。
所以为了实现你要找的东西,我们需要能够获得接口成员的编译时类型信息。据我所知,没有办法做到这一点。当有一个,这是可能的,但在那之前我不相信它。
答
令人惊讶的是答案是:什么都不做。
function isSomeType<T extends KnownAction>(x: T):T {
return x;
}
基本上打字稿会自动干扰类型,每当函数与上述签名被调用。
编辑:
let knownAction: actions.KnownAction = { type: "LOAD_TODOS_ACTION" }; // KnownAction type
let knownAction2 = isSomeType(knownAction) // LoadTodosAction type
这是不可能做到这一点这种方式,因为类型别名不是在运行时可用。 – MistyK