简体   繁体   中英

How define an Interface with Optional values, but one of them Mandatory - TypeScript

How can I define a TypeScript Interface that has a few Optional values, BUT one (or more) of them is Mandatory ???

Let's say I have the following code:

interface ISearchKey
{
  name?: string;
  id?: number;
}

function findItem(search: ISearchKey): Item 
{
  // ... 

  return ...
}

and I would like the object that implements the ISearchKey interface, to have a "name" value and/or an "id" value. One of them ("name" and "id") can be emitted, but not both!

I know I can solve this by validating the input inside the findItem() function:

let name = search.name || "";
let id   = search.id   || -1;

or any other type of input validation, but can this be done using TypeScript type validation ?

Union the types, eg

type ISearchKey = { name: string } | { id: number }

const test = (key: ISearchKey) => console.log(key);

test({ name: "name" });
test({ id: 12 });
test({ name: "name", id: 12 });
test({ fail: true }); // Errors

For required properties, you can intersect:

// With mandatory data
type ISearchKey2 = ({ name: string } | { id: number }) & { data: any };

const test2 = (key: ISearchKey2) => console.log(key);

test2({ name: "name" }); // Error
test2({ name: "name", data: 0 });
test2({ id: 12 }); // Error
test2({ id: 12, data: 1 });
test2({ name: "name", id: 12 }); // Error
test2({ name: "name", id: 12, data: 2 });
test2({ fail: true }); // Still Errors

As @jcalz noted, these unions allow for different typing of the other property, as long as one of the properties is there, eg

{ name: "name", id: "not a number!" }

A more correct type union would be:

{name: string, id?: number} | {name?: string, id: number}

This will retain the correct type of the optional properties.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM