Enforce that an array is exhaustive over a union type

后端 未结 2 1471
长发绾君心
长发绾君心 2021-01-13 20:23

Given a strongly-typed tuple created using a technique such as described here:

const tuple = (...args: T) => args;
const furnitu         


        
2条回答
  •  暗喜
    暗喜 (楼主)
    2021-01-13 20:44

    There are ways of doing this but it might be a bit messy for you. The two stumbling blocks here are the absence of partial type parameter inference and invalid types. Here is my solution:

    type Furniture = 'chair' | 'table' | 'lamp' | 'ottoman';
    
    const exhaustiveStringTuple = () =>
      (
        ...x: L & ([T] extends [L[number]] ? L : [
          Error, "You are missing ", Exclude])
      ) => x;
    
    const missingFurniture = exhaustiveStringTuple()('chair', 'table', 'lamp');
    // error, [string, string, string] is not assignable to parameter of type
    // ["chair", "table", "lamp"] & [Error, "You are missing", "ottoman"]
    
    const extraFurniture = exhaustiveStringTuple()(
        'chair', 'table', 'lamp', 'ottoman', 'bidet');
    // error, "bidet" is not assignable to a parameter of type 'Furniture'
    
    const furniture = exhaustiveStringTuple()('chair', 'table', 'lamp', 'ottoman');
    // okay
    

    As you can see, exhaustiveStringTuple is a curried function, whose sole purpose is to take a manually specified type parameter T and then return a new function which takes arguments whose types are constrained by T but inferred by the call. (The currying could be eliminated if we had proper partial type parameter inference.) In your case, T will be specified as Furniture. If all you care about is exhaustiveStringTuple(), then you can use that instead:

    const furnitureTuple = 
      (
        ...x: L & ([Furniture] extends [L[number]] ? L : [
        Error, "You are missing ", Exclude])
      ) => x;
    
    const missingFurniture = furnitureTuple('chair', 'table', 'lamp');
    // error, [string, string, string] is not assignable to parameter of type
    // ["chair", "table", "lamp"] & [Error, "You are missing", "ottoman"]
    
    const extraFurniture = furnitureTuple('chair', 'table', 'lamp', 'ottoman', 'bidet');
    // error, "bidet" is not assignable to a parameter of type 'Furniture'
    
    const furniture = furnitureTuple('chair', 'table', 'lamp', 'ottoman');
    // okay
    

    The other issue is that the error you get when you leave out a required argument is

提交回复
热议问题