2016-01-15 4 views
2

Что такое правильный тип в TypeScript для обозначения некоторых атрибутов как ? Скажем, у нас есть некий объект, который должен содержать идентификатор поля, но может также иметь много других полей, как он хочет:Установить необходимые атрибуты в TypeScript

interface SomeType { 
    id: number; 
} 

let obj: SomeType = { name: "OBJ" };   // GOOD ERROR! We must have `id` 
let obj: SomeType = { id: 123 };    // OK 
let obj: SomeType = { id: 123, name: "OBJ" }; // BAD ERROR! I just want to add a name 

Я знаю, что вы можете сделать дополнительные атрибуты со знаком вопроса, как это :

interface SomeType { 
    id: number; 
    name?: string; 
    engine?: string; 
    mother?: string; 
} 

Но я не хочу, чтобы каждый раз изменял этот интерфейс, добавляя и смешивая с ним несвязанные вещи.

Другой вариант, конечно, создать рой интерфейсов каждый проходящими основного, но это звучит как много строк кода:

interface SomeType { 
    id: number; 
} 

interface FirstType extends SomeType { 
    name: string; 
} 

Сначала я пытался сделать это:

interface SomeType extends any { 
    id: number; 
} 

Но TypeScript не может найти имя any. Может быть, есть что-то подобное с восклицательным знаком?

interface SomeType { 
    id!: number; 
} 

UPDATE

Я использую этот тип интерфейса при создании Redux действий, которые должны иметь свойство type и любое количество других дополнительных атрибутов. Есть действительно много действий, поэтому я не хотел использовать any как тип.

+2

* «Установить необходимые атрибуты» * - Вы уверены, что * это то, что вы хотите сделать? Это звучит больше для меня, как будто вы хотите определить тип, который имеет некоторые (необходимые) свойства, но допускает любое количество дополнительных не ранее определенных свойств. Пожалуйста, покажите способы использования того, как вы на самом деле хотите использовать этот тип, чтобы мы получили, для чего вы хотите это сделать. – poke

ответ

3

Вы можете использовать indexer для этого:

interface SomeType { 
    id: number; 
    [key: string]: any; 
} 

let obj1: SomeType = { name: "OBJ" };   // GOOD ERROR! We must have `id` 
let obj2: SomeType = { id: 123 };    // OK 
let obj3: SomeType = { id: 123, name: "OBJ" }; // OK 

[Playground]

Однако, обратите внимание, что даже следующий код (т.е. с ключевым свойством нестроковой) справедливо с индексом выше:

let obj4: SomeType = { id: 123, 1: "OBJ" }; // also OK 

, который смущает людей, но это как есть.

+0

Большой обходной путь! Большое спасибо! –

0

Попробуйте, как показано ниже.

interface SomeType { 
    id: number; 
    [key: string]: any; 
} 
1

Но я не хочу, чтобы каждый раз изменял этот интерфейс, добавляя и смешивая с ним несвязанные вещи.

Не добавляйте и не смешивайте несвязанные вещи в одном интерфейсе. Создайте отдельные интерфейсы, а затем объедините их, если необходимо, с помощью типов пересечений.

interface FirstType { 
    id: number; 
} 

interface SecondType { 
    name: string; 
} 

let myIntersectionObj: FirstType & SecondType = { 
    id: 2, 
    name: "some string" 
}; 

Это полезно в таких ситуациях:

function myFirstFunction(obj: FirstType) { /* does something */ } 
function mySecondFunction(obj: SecondType) { /* does something */ } 

function myFunction(obj: FirstType & SecondType) { 
    myFirstFunction(obj); 
    mySecondFunction(obj); 
} 

myFunction(myIntersectionObj); 

Использование типов пересечений помогает убедиться, что все напечатано в приложении, которое поможет избежать ошибок.Индексированные типы в идеале должны использоваться только для объектов с ключевыми значениями.

+0

Спасибо за ваш вклад, действительно узнали что-то новое о комбинации интерфейсов! Но все равно придется принять еще один, поскольку именно это я и просил. – mseimys

Смежные вопросы