【问题标题】:Can I both declare a broad type and use inferred type in typescript?我可以在打字稿中声明一个广泛的类型并使用推断类型吗?
【发布时间】:2017-10-09 16:13:07
【问题描述】:

我经常发现我想声明一个常量对象是某种广泛的类型,以便编译器可以检查初始化。但是当我 使用 那个对象时,我想使用特定的 inferred 类型。如果我为它声明一个类型,我将无法访问对象的推断类型。示例:

电子表格由指向 CSS 属性集合的字符串组成。初始化电子表格时,我想强制每个样式的成员都是 CSS 属性。所以:

type MyStyleDeclaration<K extends string = string> = { [key in K]: CSSProperties }

const myStyleSheet:MyStyleDeclaration {
    aStyle: { margin: 4 }
}

这会强制我的 CSS 属性 margin 存在,但如果我以后愚蠢地尝试访问

myStyleSheet.notAStyle

编译器不知道有什么问题 - 键可以是任何字符串。

另一方面,如果我不声明myStyleSheet 的类型,编译器将正确检测到像myStyleSheet.notAStyle 这样的错误引用。如果我将 myStyleSheet 传递给一个通用函数,声明为 MyStyleDeclaration&lt;K&gt;K 将被正确推断为只是对象中的键。

当然,现在编译器不会检测到任何错误:

const myStyleSheet {
    aStyle: { notAProperty: 4 }
}

有什么方法可以让我的蛋糕也吃吗?

【问题讨论】:

    标签: typescript type-inference inferred-type


    【解决方案1】:

    有什么方法可以让我的蛋糕也吃吗?

    我能想到的最好的就是这个装置:

    class Checker<DeclaredType> {
        check<InferredType extends DeclaredType>(t: InferredType): InferredType {
            return t;
        }
    }
    

    你可以这样使用它:

    type CSSProperties = { margin: number };
    
    type MyStyleDeclaration<K extends string = string> = {[key in K]: CSSProperties }
    
    const myStyleSheet1 = new Checker<MyStyleDeclaration>().check({
        aStyle: { notAProperty: 4 }
    });
    
    // Argument of type '{ aStyle: { notAProperty: number; }; }' is not assignable 
    // to parameter of type 'MyStyleDeclaration<string>'.
    //   Property 'aStyle' is incompatible with index signature.
    //     Type '{ notAProperty: number; }' is not assignable to type 'CSSProperties'.
    //       Object literal may only specify known properties, and 'notAProperty' 
    //       does not exist in type 'CSSProperties'.
    
        let p1 = myStyleSheet1.notAStyle;
    // no error, but myStyleSheet1 has already failed type checking, so anyway...
    
    const myStyleSheet2 = new Checker<MyStyleDeclaration>().check({
        aStyle: { margin: 4 }
    });
    // ok
    
    let p2 = myStyleSheet2.notAStyle;
    // Property 'notAStyle' does not exist on type '{ aStyle: { margin: number; }; }'.
    

    我一点也不喜欢这个。

    首先,它为每次检查添加了未使用的对象创建和方法调用,但我认为运行时开销是无法避免的。毕竟,您希望拥有未内置于语言中的检查。

    第二,它很冗长——你不能仅仅通过一个函数调用来进行自定义检查。不幸的是,当一个参数是从实际参数推断出另一个参数是显式时,Typescript 不允许使用具有两个泛型参数的泛型函数。所以你必须有一个具有一个泛型参数的类,以及具有另一个泛型参数的非静态方法(因为不允许静态类方法访问泛型类参数),这导致语法冗长new Checker&lt;SomeType&gt;().check({...})。看起来太像 Java了。


    更新

    确实正如 Ed Staub 所说,它可以简化:

    type CSSProperties = { margin: number };
    
    type MyStyleDeclaration<K extends string = string> = {[key in K]: CSSProperties }
    
    function checker<DeclaredType>() {
      return function<InferredType extends DeclaredType>(t: InferredType):InferredType{
          return t;
      }
    }
    
    const styleChecker = checker<MyStyleDeclaration>();
    
    const myStyleSheet1 = styleChecker({
        aStyle: { notAProperty: 4 }
    });
    

    【讨论】:

    • 不错的方法!我认为也许返回“检查”函数而不是类的高阶函数可能会解决一些缺点。我会留给你一天,以防你有兴趣追逐它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-23
    • 2020-06-08
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 2020-03-22
    • 1970-01-01
    相关资源
    最近更新 更多