代码之家  ›  专栏  ›  技术社区  ›  Sandy Gifford

强制非索引成员的键和值类型

  •  1
  • Sandy Gifford  · 技术社区  · 7 年前

    我有一个函数,它可以接受任何对象文字,只要对象中的所有值都是字符串:

    function getFirstLetters(obj: { [key: string]: string }): string[] {
        return Object.keys(obj).map(key => obj[key][0]);
    }
    

    这适用于任何索引类型,当我尝试使用非索引对象时会出现问题:

    interface SomeData {
        user: string;
        loc: string;
    }
    
    const someData: SomeData = {
        user: "coolGuy42",
        loc: "New York",
    };
    
    function getFirstLetters(obj: { [key: string]: string }): string[] {
        return Object.keys(obj).map(key => obj[key][0]);
    }
    
    // Argument of type 'SomeData' is not
    // assignable to parameter of type
    // '{ [key: string]: string; }'.
    // Index signature is missing in type 'SomeData'.
    getFirstLetters(someData);
    

    obj 基于它有一个索引签名,而不仅仅是它的值的类型。

    没有 询问任何使用它的人在他们的界面中包含索引签名?

    1 回复  |  直到 7 年前
        1
  •  1
  •   jcalz    7 年前

    你可以做这个函数 generic

    function getFirstLetters<T extends Record<keyof T, string>>(obj: T): string[] {
      return Object.keys(obj).map(key => obj[key][0]); // error
    }
    

    但是编译器(正确地)抱怨它不知道什么 obj[key] 可能是。毕竟 已知的 钥匙 T string -值,但TypeScript中的类型不是 exact . 类型值 {foo: string} 可能有任意数量的额外属性。我们知道 foo 财产是一种财富 一串 ,但据我们所知,它可能有一个 bar 那是一个 number

    如果您确定只将完全相同的类型传递给 getFirstLetters type assertion

    function getFirstLetters<T extends Record<keyof T, string>>(obj: T): string[] {
      // no error now
      return (Object.keys(obj) as (Array<keyof T>)).map(key => obj[key][0]);
    }
    

    getFirstLetters(someData); // no error
    

    它将拒绝具有已知属性的值,而这些属性的值不是

    getFirstLetters({a: "a", b: 23}); // error on b, not a string
    

    但请记住,您可以向它传递一些具有未知非字符串属性的内容,这些内容在运行时会导致问题:

    const whoopsie: SomeData = Object.assign({}, someData, { oops: null });
    // whoopsie is a SomeData with an extra "oops" property that the 
    // compiler has explicitly forgotten about
    
    getFirstLetters(whoopsie); // no compiler error
    // but calls null[0] at runtime and explodes!! 💥
    

    推荐文章