代码之家  ›  专栏  ›  技术社区  ›  zanona oldmanwiggins

typescript在索引签名后推断原始对象类型

  •  0
  • zanona oldmanwiggins  · 技术社区  · 5 年前

    假设我有一个对象:

    const styles = { product: { color: 'blue' } };
    

    由此推断出对象类型,我可以访问 foo.bar.baz 没有问题。

    但是,如果我想进行类型检查,我需要这样的东西:

    import type CSS from 'csstype';
    type StyleSheet = Record<string,CSS.Properties>;
    
    const styles:StyleSheet = {
        product: { color: 'blue' }
    };
    
    

    然而,当访问时,上述内容将是有效的 styles 我会得到 styles.whatever.color styles.product.margin 这是不期望的。

    考虑到这一点,Typescript中是否有任何方法可以在键入对象后推断出其原始类型,以便我可以访问其真实属性,如下所示:

    const styles:StyleSheet = { product: { color: 'blue' } }; // typed as 'StyleSheet' so I get type-checking
    styles.whatever.margin // TS thinks this is valid because of the index signature;
    
    const original = styles as OriginalObject; // infer original type so only real properties are accessible
    original.whatever // invalid (expected)
    original.product.color // valid
    
    export default original;
    

    更新

    回复@jcalx:

    Playground link

    0 回复  |  直到 5 年前
        1
  •  1
  •   jcalz    5 年前

    你要检查一下 styles 是a StyleSheet 没有 加宽 款式 样式表 让编译器忘记它的各个属性。


    一种方法是让编译器推断 款式 如果你在TypeScript不喜欢的地方使用它,相信TypeScript的结构类型系统会抱怨。也就是说,假设你有一个需要 样式表 :

    function someFunctionThatNeedsAStyleSheet(s: StyleSheet) { }
    

    您可以创建一些未注释的对象:

    const styles = { product: { color: 'gray' } };
    const badStyles = { product: { colour: 'grey' } };
    

    编译器将记住它们的属性:

    styles.whatever.margin // error;
    styles.product.color // okay
    

    稍后,当你将它们传递给函数时,它要么接受它,要么警告你:

    someFunctionThatNeedsAStyleSheet(styles); // okay
    someFunctionThatNeedsAStyleSheet(badStyles); // error!
    // ----------------------------> ~~~~~~~~~
    // Type '{ colour: string; }' has no properties in common 
    // with type 'Properties<string | 0>' 
    

    在此处进行类型检查。但当然,它不在你申报的地方 款式 变量。


    如果你想抓住一个坏 样式表 当你创建它时,你可以通过创建一个像这样的辅助函数来使用上述类型检查函数的想法:

    const asStyleSheet = <T extends StyleSheet>(t: T) => t;
    

    功能 asStyleSheet() 是一个泛型标识函数:它返回与输入类型相同的输入。但泛型类型是 constrained 样式表 ,所以如果你传入一个错误,你会得到一个错误。这样地:

    const styles = asStyleSheet({ product: { color: 'gray' } }); // okay
    const badStyles = asStyleSheet({ product: { colour: 'grey' } }) // error!
    // ---------------------------------------> ~~~~~~~~~~~~~~
    // 'colour' does not exist in type 'Properties<string | 0>'. 
    // Did you mean to write 'color' ? 
    

    通过使用 as样式表() ,您正在检查的类型 款式 不改变它;输出 as样式表() 与输入类型相同。因此编译器会记住它的属性:

    styles.whatever.margin//错误;
    styles.product.color//好的
    

    看起来不错。


    好的,希望这能有所帮助;祝你好运!

    Playground link to code