考虑这个例子:
type typeA = {
name: string
}
type typeB = {
surname: string
}
type typeC = {
age: number
}
type post = typeA | typeB | typeC
interface propTypes {
post: post
}
const App = ({ post }: propTypes) => {
post // no autocomplete
return null
}
post. 之后没有自动补全,因为你没有任何共同的道具。
见docs
如果我们有一个联合类型的值,我们只能访问联合中所有类型共有的成员。
为了让它工作,你应该定义一个typeguard:
const isTypeA = (props: unknown): props is typeA => Object.prototype.hasOwnProperty.call(props, 'name')
const App = ({ post }: propTypes) => {
if (isTypeA(post)) {
post.name // string
}
return null
}
或者,您可以使用in 运算符,它与联合非常有效:
const App = ({ post }: propTypes) => {
if ('name' in post) {
post.name // string
}
return null
}
或者你可以使用StrictUnion 输入:
type typeA = {
name: string
}
type typeB = {
surname: string
}
type typeC = {
age: number
}
// credits goes to https://stackoverflow.com/questions/65805600/type-union-not-checking-for-excess-properties#answer-65805753
type UnionKeys<T> = T extends T ? keyof T : never;
type StrictUnionHelper<T, TAll> =
T extends any
? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;
type StrictUnion<T> = StrictUnionHelper<T, T>
type Post = StrictUnion<typeA | typeB | typeC>
interface propTypes {
post: Post
}
const App = ({ post }: propTypes) => {
if (post.name) {
post.name // string
}
return null
}
Playground
'in' 运算符为我工作
请记住,它有自己的缺点:
type typeA = {
name?: string
}
interface propTypes {
post: typeA
}
const App = ({ post }: propTypes) => {
if ('name' in post) {
post.name.charAt // error
}
return null
}
它与联合完全兼容,但不适用于可选属性。