[英]creating typescript type “one of interfaces”
I need to create type which it's behaviour would be choosing between one of given interfaces.我需要创建其行为将在给定接口之一之间进行选择的类型。
Please note: in the example below someTask
is data returned from the server: There is no actual initiation of it in the code!请注意:下例中
someTask
是从服务器返回的数据:代码中并没有实际启动它! For example:例如:
interface TaskA { foo: string }
interface TaskB { fee: string }
type Task = TaskB | TaskB
const task:Task = someTask
console.log(task.fee)
The console.log
function will yell at me: console.log
function 会冲我大喊:
Property 'fee' does not exist on type 'Task'.
“任务”类型上不存在属性“费用”。
What am I doing wrong here?我在这里做错了什么?
The terms "union" and "intersection" as used in Typescript are mathematically correct, but still a bit confusing when applied to objects/interfaces. Typescript 中使用的术语“联合”和“交集”在数学上是正确的,但在应用于对象/接口时仍然有点混乱。 A union of two interfaces A and B is a type for all objects which are A or B. To work with such type reliably, the compiler has to be sure that only keys that are present in both A and B are used.
两个接口 A 和 B 的联合是所有对象 A 或 B 的类型。要可靠地使用这种类型,编译器必须确保只使用 A 和 B 中都存在的键。 In other words, a union of objects contains only an intersection of their keys.
换句话说,对象的联合只包含它们的键的交集。 Conversely, an intersection of A and B,
A & B
, contains all keys from both A and B, that is, an intersection of interfaces is a union of their keys:相反,A 和 B 的交集
A & B
包含来自 A 和 B 的所有键,也就是说,接口的交集是它们键的并集:
type A = { a: 1, b: 2, x: 3 }
type B = { a: 1, b: 2, y: 3 }
type U = keyof (A | B) // a|b
type I = keyof (A & B) // a|b|x|y
Since your objects don't have any common keys, their union is essentially an empty object ( {never: any}
).由于您的对象没有任何公用键,因此它们的联合本质上是一个空的 object (
{never: any}
)。 It cannot have any properties.它不能有任何属性。
What you can do, is to introduce a tagged union, in which all member types have a common property ("tag") which enables the compiler to differentiate between them.您可以做的是引入一个标记联合,其中所有成员类型都有一个公共属性(“标记”),使编译器能够区分它们。 Example:
例子:
type SomeTask<T, P extends {}> = { type: T } & P
type TaskOne = SomeTask<'first', {
one: number
}>
type TaskTwo = SomeTask<'second', {
two: number
}>
type Task = TaskOne | TaskTwo;
function validateTask(t: Task) {
if (t.type === 'first')
console.log(t.one);
if (t.type === 'second')
console.log(t.two);
}
Here, the compiler knows, that if the type
is first
, then the object is expected to have the one
property.在这里,编译器知道,如果
type
是first
,那么 object 应该具有one
属性。
If you can't be sure that the object you get from your server is a Task, you should add a User Defined Type Guard for either TaskA or TaskB.如果您不能确定您从服务器获得的 object 是一个任务,您应该为 TaskA 或 TaskB 添加一个用户定义的类型保护。 That way you can be sure that
someTask
has fee
as a property, in this case.在这种情况下,您可以确定
someTask
作为属性具有fee
。
interface TaskA { foo: string }
interface TaskB { fee: string }
type Task = TaskA | TaskB
const task: Task = {fee: 'bar'};
console.log(isTaskA(task) ? task.foo : task.fee)
function isTaskA(value: TaskA | TaskB): value is TaskA {
return value.hasOwnProperty('foo');
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.