我需要创建其行为将在给定接口之一之间进行选择的类型。
请注意:在下面的示例中,someTask
是从服务器返回的数据!代码中没有实际启动它!
例如:
interface TaskA { foo: string }
interface TaskB { fee: string }
type Task = TaskB | TaskB
const task:Task = someTask
console.log(task.fee)
console.log
函数会对我大喊:
类型“任务”上不存在属性“费用”。
我在这里做什么错了?
答案 0 :(得分:1)
Typescript中使用的术语“联合”和“交集”在数学上是正确的,但是当应用于对象/界面时仍然有些混乱。两个接口A和B的并集是A或B所有对象的一种类型。为了可靠地使用这种类型,编译器必须确保仅使用A和B中都存在的键。换句话说,对象的并集仅包含其键的交集。相反,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
由于您的对象没有任何公共键,因此它们的并集本质上是一个空对象({never: any}
)。它不能具有任何属性。
您可以做的是引入一个 tagged 联合,其中所有成员类型都具有一个公共属性(“标记”),使编译器可以区分它们。示例:
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);
}
在这里,编译器知道,如果type
是first
,则该对象应该具有one
属性。
答案 1 :(得分:0)
答案 2 :(得分:0)
如果不能确定从服务器获取的对象是任务,则应为TaskA或TaskB添加用户定义类型防护。这样,在这种情况下,您可以确定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');
}