Pavlo
Pavlo

Reputation: 1197

TypeScript: Union type of objects without defining the whole type on each side

I am converting frontend Java to TypeScript and i am dealing with method overloading.

I want to write the types like this

const person = (info: {name:string, age:number} | {man:boolean}): void => {
    if (typeof info.man === "boolean") {
        console.log("man is defined", info.man);
    } else {
        console.log(info.name, info.age);
    }
}

person({name:"Joe", age:25});
person({ man: false});

But i have it like this to make TypeScript happy

const person = (info: {name:string, age:number, man?:undefined} 
  | {name?:string, age?:number, man:boolean}): void => {
    if (typeof info.man === "boolean") {
        console.log("man is defined", info.man);
    } else {
        console.log(info.name, info.age);
    }
}

person({name:"Joe", age:25});
person({ man: false});

I am hoping that there is a prettier way to define the types to make it more readable

Upvotes: 1

Views: 79

Answers (2)

cyr_x
cyr_x

Reputation: 14257

You could go with default function overloading here, not exactly like your desired example, but much more readable:

function person(info: { man: boolean }): void;
function person(info: { name: string, age: number }): void;
function person(info: any): void {
    if (typeof info.man === "boolean") {
        console.log("man is defined", info.man);
    } else {
        console.log(info.name, info.age);
    }
}

The way this works is, that the compiler hides the signature of the implementation and uses the overloaded signatures for type checking.

Upvotes: 2

Tao
Tao

Reputation: 2242

TypeScript actually supports method overloading by specifying multiple function signatures. The last signature is the actual implemenation and will be hidden by the compiler.

function person(info: { name: string, age: number }): void;
function person(info: { man: boolean }): void;
function person(info: any) {
    if (typeof info.man === "boolean") {
        console.log("man is defined", info.man);
    } else {
        console.log(info.name, info.age);
    }
}

If you prefer to assign an arrow function you can define the overloads in a separate type.

type Person = {
    (info: { man: boolean }): void,
    (info: { name: string, age: number}): void,
}
const person: Person = (info: any) => {
    if (typeof info.man === "boolean") {
        console.log("man is defined", info.man);
    } else {
        console.log(info.name, info.age);
    }
}

Upvotes: 2

Related Questions