【问题标题】:optional type with generic in typescript打字稿中具有泛型的可选类型
【发布时间】:2020-09-09 14:28:37
【问题描述】:

[我想要]


interface T {
    a?: string;
    b?: number;
    c?: boolean;
    d?: object;
    e?: null;
}

type A = {
    a: string;
    b: number;
    q: string; // not exist in type T
}


type B = {
    a: string;
    b: number;
}

type G<U extends T> = {
  data: U;
  creator: () => void;
}

const someFunc = <U>(data: U): G<U> => {
  return {
      data,
      creator: () => { console.log(data ) }
  }
}

const funcA = (data: A) => {
    const something = someFunc<A>(data); // I want to occur error
}

const funcB = (data: B) => {
    const something = someFunc<B>(data); // I want to do well
}

类型“T”具有可选属性(每个属性)。

一个类型是类型“T”的子集(是“B”)

另一个不是“T”类型的子集(是“A” - 具有属性“q”)

但是,使用类型“B”不会发生错误。

怎么办?

谢谢。

【问题讨论】:

    标签: typescript generics


    【解决方案1】:

    没有错误的原因就是我们所说的U extends T,这意味着-“我接受任何具有T所有属性的U”。我们的 T 是非常松散的类型,每个属性都是可选的,那么只有这些属性的一部分的类型是完全可以的,因为原始的 T 从未说过字段是强制性的。让我们做类型级别的检查来证明我的话:

    type AextendsT = A extends T ? true : false; // true
    type BextendsT = B extends T ? true : false; // true
    

    你可以问 - 为什么如果 A 有额外的字段。是的,它有,但它也符合 T 的所有要求,这个附加字段不会破坏 T 的所有属性都在 A 中的事实。同样从实际的思维方式来看,如果我们使用属性让我们说 a 和 b,那么如果对象有 q,这不是问题,因为我们不使用这个属性,所以不会发生任何不好的事情。

    仅供参考。除了对键的迭代之外,禁止附加属性没有真正的实际意义。但如果您对此感兴趣,这里有完整的解决方案 - Advanced TypeScript Exercises - Answer 7

    【讨论】:

      【解决方案2】:

      如果对象存储在变量中,FYI Typescript 允许过多的属性:

      绕过这些检查的最后一种方法,可能有点 令人惊讶的是,将对象分配给另一个变量:因为 squareOptions 不会进行过多的属性检查,编译器不会 给你一个错误。 https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks

      因此,即使您的函数期待 T,它也会起作用:

      interface T {
        a?: string;
        b?: number;
        c?: boolean;
        d?: object;
        e?: null;
      }
      
      interface A {
        a: string;
        b: number;
        q: string; // not exist in type T
      }
      
      const foo: A = {
        a: "a",
        b: 1,
        q: "q",
      };
      
      const someFunc = (data: T) => console.log(data);
      
      someFunc(foo);
      

      在您的示例中,它“更有效一点”,因为您期望任何扩展 T(在此行中为 type G&lt;U extends T&gt; = {)的东西,这意味着任何尊重接口 T 和 A 的东西。

      其他说明:你的函数someFunc对U类型没有限制,所以它可以接受任何东西:

      const funcC = (data: number) => {
          const something = someFunc<number>(data); // Also valid
      }
      

      为了最终回答您的问题并能够禁止额外的属性,这里有一个详细的答案:https://stackoverflow.com/a/57117594/3292234

      【讨论】:

        猜你喜欢
        • 2021-12-30
        • 2020-08-03
        • 2021-11-26
        • 2022-08-06
        • 2017-12-14
        • 1970-01-01
        • 1970-01-01
        • 2018-10-17
        • 2020-06-08
        相关资源
        最近更新 更多