【问题标题】:Is there a way to "extract" the type of TypeScript interface property?Is there a way to \"extract\" the type of TypeScript interface property?
【发布时间】:2022-07-14 18:20:36
【问题描述】:

Let's suppose there's a typing file for library X which includes some interfaces.

interface I1 {
    x: any;
}
    
interface I2 {
    y: {
        a: I1,
        b: I1,
        c: I1
    }
    z: any
}

In order to work with this library I need pass around an object that is of exactly the same type as I2.y. I can of course create identical interface in my source files:

interface MyInterface {
    a: I1,
    b: I1,
    c: I1
}

let myVar: MyInterface;

but then I get the burden of keeping it up to date with the one from library, moreover it can be very large and result in lot of code duplication.

Therefore, is there any way to "extract" the type of this specific property of the interface? Something similar to let myVar: typeof I2.y (which doesn't work and results in "Cannot find name I2" error).


Edit: after playing a bit in TS Playground I noticed that following code achieves exactly what I want to:

declare var x: I2;
let y: typeof x.y;

However it requires a redundant variable x to be declared. I am looking for a way to achieve this without that declaration.

【问题讨论】:

  • which doesn't work- how does that manifest? What's the actual error message that you see?
  • @BartekBanachewicz updated

标签: typescript typing definitelytyped


【解决方案1】:

It wasn't possible before but luckily it is now, since TypeScript version 2.1. It has been released on the 7th of December 2016 and it introducesindexed access typesalso calledlookup types.

The syntax looks exactly like element access but written in place of types. So in your case:

interface I1 {
    x: any;
}

interface I2 {
    y: {
        a: I1,
        b: I1,
        c: I1
    }
    z: any
}

let myVar: I2['y'];  // indexed access type

Now myVar has type of I2.y.

Check it out in TypeScript Playground.

【讨论】:

  • In the case when 'y' is an array, is there any way to extract the type of the elements? e.g. I2{ y: {..}[]}
  • @JohnB yes, you can do it in exactly same way, because array indices are just like object properties. Check it out here: typescriptlang.org/play/…
  • @JohnB yes, you can access it the same way ie. I2['y'][0] See: typescriptlang.org/play/…
  • This is really awesome ability
  • Let's assume we're looping over keys of an object defined using I2 as the type. How would I get the type of a specific key dynamically when looping. This; let z: typeof x[a];, where a is a certain key as a string, does not work. It tells me that a refers to a value and has to refer to a type. How would I go about doing this? Is it even possible in any way? Thx!
【解决方案2】:

To expand on the accepted answer, you can also assign the type using the type keyword and use it in other places.

// Some obscure library
interface A {
  prop: {
    name: string;
    age: number;
  }
}

// Your helper type
type A_Prop = A['prop']

// Usage
const myThing: A_prop = { name: 'June', age: 29 };

【讨论】:

    【解决方案3】:

    Just an example of extracting a literal type from theunion object type:

    type Config = {
        key: "start_time",
        value: number,
    } | {
        key: "currency",
        value: string,
    }
    
    export type ConfigKey = Config["key"];
    // "start_time"|"currency"
    
    

    【讨论】:

    • This is the answer I was looking for. I wounder why it's not upvoted. Anyway, thank you!
    【解决方案4】:

    keyof Colors will return a list of all keys "white" | "black". When this list of keys gets passed to the Colors interface, the type will be all the values of the given keys, "#fff" | #000.

    interface Colors {
      white: "#fff"
      black: "#000"
    }
    
    type ColorValues = Colors[keyof Colors]
    // ColorValues = "#fff" | "#000"
    

    【讨论】:

      【解决方案5】:

      An interface is like the definition of an object. Then y is a property of your I2 object, that is of a certain type, in that case "anonymous".

      You could use another interface to define y and then use it as your y type like this

      interface ytype {
         a: I1;
         b: I1;
         c: I1;
      }
      
      interface I2 {
          y: ytype;
          z: any;
      }
      

      You can put your interface in a file and use extract so you can import it in other files of your projects

      export interface ytype {
         a: I1;
         b: I1;
         c: I1;
      }
      
      
      
       export interface I2 {
              y: ytype;
              z: any;
          }
      

      You can import it that way :

         import {I1, I2, ytype} from 'your_file'
      

      【讨论】:

      • Everything's fine, but as I mentioned - the interfaces I1 and I2 come from an external library and are defined in d.ts file for that library. Therefore having this ytype interface would be a code duplication and would need to be constantly updated.
      猜你喜欢
      • 2022-12-27
      • 2022-12-02
      • 1970-01-01
      • 2022-12-01
      • 2022-12-02
      • 2022-12-27
      • 2022-12-01
      • 2022-12-02
      • 2022-12-02
      相关资源
      最近更新 更多