你的Props 类型应该是严格联合类型。
import React, { FC } from 'react'
// credits goes 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 Props<T, S> = StrictUnion<{
data: T[]
} | {
data: T[]
additionalData: S
}>
type Bike = {
color: string
}
type BikeShed = {
model: string
}
const Foo = <T, S = void>(props: Props<T, S>) => {
const { additionalData } = props // ok, but may be undefined
const { data } = props; // ok
return null
}
const bikes: Bike[] = []
const bikeShed = { model: '' }
const component = <Foo<Bike, BikeShed> data={[]} />
Playground
更多关于在 React 中处理 union props 的信息你可以在我的blog找到
更新
你也可以试试typeguards:
import React, { FC } from 'react'
type WithoutAdditional<T> = {
data: T[]
}
type WithAdditional<T, S> = {
data: T[]
additionalData: S
}
type Props<T, S> =
| WithAdditional<T, S>
| WithoutAdditional<T>
const hasProperty = <Obj, Prop extends string>(obj: Obj, prop: Prop): obj is Obj & Record<Prop, unknown> =>
Object.prototype.hasOwnProperty.call(obj, prop)
const withAdditional = <T, S>(obj: Props<T, S>): obj is WithAdditional<T, S> => hasProperty(obj, 'additionalData')
type Bike = {
color: string
}
type BikeShed = {
model: string
}
const Foo = <T, S = void>(props: Props<T, S>) => {
if (withAdditional(props)) {
const x = props; // WIthAdditional
} else {
const y = props; // WIthoutAdditional
}
return null
}
const bikes: Bike[] = []
const bikeShed = { model: '' }
const component = <Foo<Bike, BikeShed> data={[]} />
Playground 2