我有一个简单的问题:是否可以在TypeScript中获得联合的一部分的类型?
例如,您经常可以使用如下查询类型:
interface Person {
name: string;
}
type Name = Person['name']
现在,我假设这样的联合是不可能的:
type Entity =
{ __type: 'Company', name: string }
| { __type: 'Employee', firstName: string };
那么,有什么方法可以获取工会的一部分吗?像这样:
type Company = DoTheMagic<Entity, { __type: 'Employee' }>
const company: Company = ...;
console.log(company.name) // OK
console.log(company.firstName) // Compile error
答案 0 :(得分:2)
我们可以使用条件类型Extract<T, U>
。如果T
是联合,则Extract
的结果将是T
联合的所有成员,满足约束U
(又名T extends U
)>
type Company = Extract<Entity, { __type: 'Employee' }>
// Same as
type Company = {
__type: "Employee";
firstName: string;
}
答案 1 :(得分:1)
正确答案由 Titian Cernicova-Dragomir发布。 但是,我决定为我的更广泛的问题发布完整的解决方案。
我们正在与ApolloClient合作,我们经常收到工会。由于要进行强类型输入,因此需要很多难看的条件才能访问正确的属性并保持TypeScript满意。
因此,我想到了以下 asTypeGuard 函数:
function asTypeGuard<Typename extends string>(typename: Typename) {
return function<Entity extends { __typename: string }>(
entity: Entity
): entity is Extract<Entity, { __typename: typeof typename }> {
return entity.__typename === typename;
};
}
const isCompany = asTypeGuard('Company');
const isEmployee = asTypeGuard('Employee');
let entity: { __typename: 'Company'; name: string } | { __typename: 'Employee'; firstName: string };
if (isCompany(entity)) {
console.log(entity.name);
console.log(entity.firstName) // Property 'firstName' does not exist on type '{ __typename: "Company"; name: string; }
} else if (isEmployee(entity)) {
console.log(entity.name); // Property 'name' does not exist on type '{ __typename: "Employee"; firstName: string; }
console.log(entity.firstName)
}