I want to have a component Foo that accepts two types of props:
Foo({a: 'a'})Foo({a: 'a', b: 'b', c:'c'})where {a: 'a'} is required.
These should invalid
Foo({a: 'a', b: 'b'}) // ❌
Foo({a: 'a', c: 'c'}) // ❌
Here is my attempt.
type BaseProps = {
a: "a";
};
type VariantPrps = {
b: "b";
c: "c";
} & BaseProps;
function Foo(props: BaseProps): React.ReactNode;
function Foo(props: VariantPrps): React.ReactNode;
function Foo(props: BaseProps | VariantPrps) {
// I can only access `props.a` inside
return <span>{props.a}</span>;
}
// usage
Foo({a: 'a'}) // ✅
Foo({a: 'a', b: 'b', c:'c'}) // ✅
Foo({a: 'a', b: 'b'}) // ❌
Foo({a: 'a', c: 'c'}) // ❌
it works to some extent but inside Foo I can only access a, not b and c. My intention is that inside that component I should be able to access b and c and check to see if they exist or not before using them. Is there a way to do that?
Consider this example:
import React from 'react'
// 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 BaseProps = {
a: "a";
};
type VariantPrps = {
b: "b";
c: "c";
} & BaseProps;
function Foo(props: BaseProps): React.ReactNode;
function Foo(props: VariantPrps): React.ReactNode;
function Foo(props: StrictUnion<BaseProps | VariantPrps>) {
props.a // "a"
props.b // "b" | undefined
props.c // "c" | undefined
// I can only access `props.a` inside
return <span>{props.a}</span>;
}
// usage
Foo({ a: 'a' }) // ✅
Foo({ a: 'a', b: 'b', c: 'c' }) // ✅
Foo({ a: 'a', b: 'b' }) // ❌
Foo({ a: 'a', c: 'c' }) // ❌
You were allowed to use only a property because it is common property for both types.
See docs