Home > OS >  Condition type if array includes all keys of interface
Condition type if array includes all keys of interface

Time:06-30

interface IYears {
  one: string;
  two: string;
  three: string;
}

function transformYears(years: Array<keyof IYears>): [if all items of "years" includes in keyof IYears] ? IYears : Partial<IYears> {
  return years.reduce((acc, year) => ({
    ...acc,
    [year]: 'foo'
  }), {})
}

const yearsFirst = transformYears(['one', 'two']) // type of yearsFirst is Partial<IYears>

const yearsSecond = transformYears(['one', 'two', 'three']) // type of yearsFirst is IYears

How modified transformYears to match type of yearsFirst and yearsSecond? And possible check condition "if all items of "years" includes in keyof IYears" in ts?

CodePudding user response:

You need to make the function generic to get this to work.

function transformYears<
  Y extends (keyof IYears)[]
>(years: [...Y]): Exclude<keyof IYears, Y[number]> extends never 
  ? IYears 
  : Partial<IYears> 
{
  return years.reduce((acc, year) => ({
    ...acc,
    [year]: 'foo'
  }), {}) as any
}

If we store the passed array in the generic type Y, we can use Exclude to compute the difference between keyof IYears and Y[number]. If Y[number] contains all keys of IYears, this evaluates to never which we can check for in the condition.

Playground


After thinking about it, we can make it even a bit shorter:

function transformYears<
  Y extends (keyof IYears)[]
>(years: [...Y]): keyof IYears extends Y[number] ? IYears : Partial<IYears> {
  return years.reduce((acc, year) => ({
    ...acc,
    [year]: 'foo'
  }), {}) as any
}

Playground

  • Related