Чи є спосіб "витягти" тип властивості інтерфейсу TypeScript?


124

Припустимо, є файл набору тексту для бібліотеки X, який включає деякі інтерфейси.

interface I1 {
    x: any;
}

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

Для роботи з цією бібліотекою мені потрібно передати об'єкт, який має абсолютно той самий тип, що і I2.y. Звичайно, я можу створити ідентичний інтерфейс у своїх вихідних файлах:

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

let myVar: MyInterface;

але тоді я отримую тягар підтримати його в курсі того, що з бібліотеки, до того ж він може бути дуже великим і призвести до великої кількості копій коду.

Отже, чи є спосіб "витягти" тип цієї специфічної властивості інтерфейсу? Щось схоже на let myVar: typeof I2.y(що не працює і призводить до помилки "Не вдається знайти ім'я I2"). Заздалегідь спасибі.


Редагувати : трохи погравши в TS Playground, я помітив, що наступний код досягає саме того, що я хочу:

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

Однак для цього потрібно xоголосити надлишкову змінну . Я шукаю спосіб досягти цього без цієї заяви.


1
що не працює - як це проявляється? Яке фактичне повідомлення про помилку ви бачите?
Бартек Баначевич,

@BartekBanachewicz оновлено
Куба

Відповіді:


251

Раніше це було неможливо, але на щастя це можливо зараз, оскільки TypeScript версії 2.1 . Він був випущений 7 грудня 2016 року і в ньому представлені індексовані типи доступу, які також називаються типами пошуку .

Синтаксис виглядає точно так само, як доступ до елементів, але записаний замість типів. Отже, у вашому випадку:

interface I1 {
    x: any;
}

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

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

Зараз myVarмає типI2.y .

Перевірте це на TypeScript Playground .


1
У випадку, коли 'y' - це масив, чи є спосіб виділити тип елементів? напр. I2 {y: {..} []}
Джон Б,

1
@JohnB так, ви можете зробити це точно таким же чином, оскільки індекси масивів точно такі ж, як властивості об'єкта. Подивіться тут: typecriptlang.org/play/…
Куба Ягода

3
@JohnB так, ви можете отримати до нього такий же спосіб, тобто. I2['y'][0]Див: typescriptlang.org/play / ...
Міхал Miszczyszyn

2
Це дійсно приголомшлива здатність
Geradlus_RU

1
Припустимо, ми переглядаємо ключі об’єкта, визначеного I2як тип. Як би я динамічно отримував тип конкретного ключа під час циклу. Це; let z: typeof x[a];, де aє певний ключ як рядок, не працює. Це говорить мені, що aпосилається на значення і має посилатися на тип. Як би я це зробив? Це взагалі можливо якимось чином? Дякую!
Emil Walser

-2

Інтерфейс схожий на визначення об'єкта. Тоді y - це властивість вашого об'єкта I2, тобто певного типу, в такому випадку "анонімним".

Ви можете використати інший інтерфейс для визначення y, а потім використовувати його як ваш тип y, наприклад

interface ytype {
   a: I1;
   b: I1;
   c: I1;
}

interface I2 {
    y: ytype;
    z: any;
}

Ви можете розмістити свій інтерфейс у файлі та використовувати витяг, щоб ви могли імпортувати його в інші файли своїх проектів

export interface ytype {
   a: I1;
   b: I1;
   c: I1;
}



 export interface I2 {
        y: ytype;
        z: any;
    }

Ви можете імпортувати його таким чином:

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

Все добре, але, як я вже згадував, інтерфейси I1 та I2 походять із зовнішньої бібліотеки і визначаються у файлі d.ts для цієї бібліотеки. Тому наявність цього інтерфейсу ytype буде копіюванням коду і його потрібно постійно оновлювати.
Куба Ягода
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.