Typescript - How Multiple Type situation in React

Viewed 168

Example Code:

type PropsType = {top: number} | {bottom: number}

// A funtion that make something run at one direction by distance.
function run(props: PropsType) {
...
}

Expected:

run({top: 100}) or run({bottom: 100})

not run({top: 100, bottom: 100}) (which is the current)

not trigger suggtion have both props: enter image description here

Question:

So, how to limit the type with different situation, I don't want the props accept top and bottom at same time.

3 Answers

You can use "never" keyword like this:

type PropsType = {top: number, bottom?: never} | {top?: never, bottom: number}

// A funtion that make something run at one direction by distance.
function run(props: PropsType) {
...
}

You can make your union more stricted:

type PropsType = { top: number } | { bottom: number }

// credits goes to Titian Cernicova-Dragomir
//https://stackoverflow.com/questions/65805600/struggling-with-building-a-type-in-ts#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>

// A funtion that make something run at one direction by distance.
function run(props: StrictUnion<PropsType>) {

}

run({ top: 100, bottom: 100 }) // error
run({ top: 100 }) // ok
run({ bottom: 100 }) // ok

If this line :

type UnionKeys<T> = T extends T ? keyof T : never;

Playground

is not clear for you, please refer to the docs

When conditional types act on a generic type, they become distributive when given a union type. If we plug a union type into ToArray, then the conditional type will be applied to each member of that union.

What about optional parameter?

type PropsType = {top?: number, bottom?: number}

Usage will be:

run({top: 100});
run({bottom: 100});
Related