简体   繁体   中英

Define typescript interface with conditional values

Let's say I want to create an interface that looks like this:

interface DataStatus<T> {
   isSuccess: boolean; 
   isError: boolean;
   data: T | undefined; 
}

And later on I'm going to be using this like:

interface Foo {
   id: string; 
   name: string; 
}

function fetchData() : DataStatus<Foo> {
   //implementation
}


const ds = fetchData(); 

if (ds.isSuccess) {
   console.log(ds.data.name); //TS Warning - ds.data might be undefined
}

What I'd like to do add some conditions to the DataStatus interface with these rules:

  • isSuccess and isError must be opposites
  • data will have value T if isSuccess is true, and be undefined if isSuccess is false

Is this kind of thing possible with typescript?

Yes, you can if you have a discriminated union.

interface ISuccessDataStatus<T> {
   isSuccess: true; 
   isError: false;
   data: T; 
}

interface IFailureDataStatus<T> {
   isSuccess: false; 
   isError: true;
   data: undefined; 
}


type PossibleStatus<T> = ISuccessDataStatus<T> | IFailureDataStatus<T>;


declare const hello: PossibleStatus<{ name: "john" }>

if (hello.isSuccess) {
    const whatType = hello.data; // T and not T | undefined
}

const whatType = hello; // PossibleDataStatus; (outside the if block)

Typescript is smart enough to figure out when hello.isSuccess is true inside that block where it knows it's true it will narrow down the type of hello to ISucessDataStatus instead of the union.

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