typescript restrict count of object's properties

前端 未结 3 1436
甜味超标
甜味超标 2020-11-30 15:05

Is it possible to restrict the count of object properties, say I want to restrict object have only one string propery (with any name), I can do:

{[index: stri         


        
相关标签:
3条回答
  • 2020-11-30 15:29

    Most likely no. The best solution that comes to my mind is wrapping an Object (or Map) with you custom class with methods set(key: string, val: any) and get(key: string) that can disallow adding new items to the underlying collection under certain circumstances.

    0 讨论(0)
  • 2020-11-30 15:36

    Because this question has been marked as a duplicate of this one, let me answer here.

    Check if a type is a union

    /**
     * @see https://stackoverflow.com/questions/53953814/typescript-check-if-a-type-is-a-union/53955431
     */
    type IsSingleton<T> =
      [T] extends [UnionToIntersection<T>]
        ? true
        : false
    
    /**
     * @author https://stackoverflow.com/users/2887218/jcalz
     * @see https://stackoverflow.com/a/50375286/10325032
     */
    type UnionToIntersection<Union> =
      (Union extends any
        ? (argument: Union) => void
        : never
      ) extends (argument: infer Intersection) => void
        ? Intersection
      : never;
    

    Allow only singleton types

    type SingletonOnly<T> =
      IsSingleton<T> extends true
        ? T
        : never
    

    Restrict a function to accept only a singleton type

    declare function foo<K extends string>(s: SingletonOnly<K>): void
    
    declare const singleton: 'foo';
    foo(singleton);
    
    declare const union: "foo" | "bar";
    foo(union); // Compile-time error
    

    TypeScript Playground

    0 讨论(0)
  • 2020-11-30 15:46

    There are many answers to this question on Stackoverflow (including this detailed one), but none of them worked for my situation, which is similar to the one posted here.

    Problem

    I have a function that takes an object. I want it to throw a Compilation Error (Typescript) if the passed object doesn't have exactly one key. e.g.

    f({}); // Must error here, as it has less than one key!
    f({ x: 5 });
    f({ x: 5, y : 6 }); // Must error here, as it has more than one key!
    

    Solution

    Using the popular UnionToIntersection and IsUnion, I achieved it via the following utility function.

    type SingleKey<T> = IsUnion<keyof T> extends true ? never : {} extends T ? never : T;
    

    Full Code:

    // From https://stackoverflow.com/a/50375286
    type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
    
    // From: https://stackoverflow.com/a/53955431
    type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;
    
    // Here we come!
    type SingleKey<T> = IsUnion<keyof T> extends true ? never : {} extends T ? never : T;
    
    // Usage:
    function f<T extends Record<string, any>>(obj: SingleKey<T>) {
        console.log({ obj });
    }
    
    f({}); // errors here!
    f({ x: 5 });
    f({ x: 5, y : 6 }); // errors here!
    

    Playground Link

    0 讨论(0)
提交回复
热议问题