2016-11-05 5 views
0

Я по-прежнему новичок в TypeScript и часто нахожу вещи, которые я нахожу очень странными.Успех выбора типа зависит от наименования значения

Возьмите этот код:

interface MyInterface<T> { 
    [i: string]: T; 
} 

function myFunc<T>(arg: MyInterface<T>) { } 

var o = { 'val1': 42, 'val2': 43 }; 

myFunc(o); 

вызов завершается с жалобой о том, что «Индекс подписи не хватает».

Интересно, что это не хватает, когда я пишу

myFunc({ 'val1': 42, 'val2': 43 }); 

Это означало бы, что выражение { 'val1': 42, 'val2': 43 } «s тип выводится в обратном направлении от вызова (который несколько прогнозное), но не так, когда связаны с именем (что странно, а не как, например, я знаю обратный вывод для работы с F #).

Но это становится еще страннее.

Если изменить интерфейс к

interface MyInterface<T> { 
    [i: number]: T; 
} 

то соответствующий

var o = [42, 43]; 

myFunc(o); 

также работает (в дополнение к прохождению массива напрямую).

Это что, дизайн? Какие правила объясняют это?

ответ

1

Причина, по которой вы видите эту несогласованность, заключается в том, что вы используете TypeScript 1.8. Если вы попробуете либо на игровой площадке TypeScript, you'll see either one works.

Причина такого поведения в TS 1.8, потому что, когда вы разместили литерал объекта непосредственно в вызове myFunc, он контекстуально напечатал по arg, тип которого имеет индекс подпись. В результате выведенный тип получил подпись индекса.

контекстная типизация не изменяет предварительно INFERRED типа переменного (объявлено типа), поэтому, когда вы пытались передать o в myFunc, вы получили сообщение об ошибке, что o отсутствовало указательная подпись.

В TypeScript 2.0 (и выше) эти сценарии были достаточно болезненны, что мы ввели концептуальную подпись подписи подписи. Посмотрите запрос на тяну здесь: https://github.com/Microsoft/TypeScript/pull/7029.

процитировать:

С помощью этого PR литерала объекта типа является назначаемым к типу с индексом подписью, если все известные свойства в объекте буквальных присваиваемы эта подпись индекса. Это позволяет передать переменную, которая была инициализирована с объектом буквального в качестве параметра функции, ожидающей карта или словарь:

function httpService(path: string, headers: { [x: string]: string }) { } 

const headers = { 
    "Content-Type": "application/x-www-form-urlencoded" 
}; 

httpService("", { "Content-Type": "application/x-www-form-urlencoded" }); // Ok 
httpService("", headers); // Now ok, previously wasn't 
подписи
+0

Но ясно, улучшение только в отношении индекса конкретно и там все еще есть разница между объявленным типом и контекстуальным типом, правильно? Я думаю, что в F # такого различия нет. – John

+1

Правильно - способ вывода типов не использует системы унификации, которые вы найдете на таких языках, как F #. Преимущество этой местности заключается в том, что легче рассуждать о том, как язык вводит тип-вывод, ограничивается уровнем оператора (хотя помните, что каждый оператор может содержать несколько операторов через выражения функций и т. П.). –