Zawsze kompiluję Typescript z flagą --noImplicitAny. Ma to sens, ponieważ chcę, aby sprawdzanie mojego typu było jak najściślejsze.
Mój problem polega na tym, że następujący kod powoduje błąd Index signature of object type implicitly has an 'any' type
:
interface ISomeObject {
firstKey: string;
secondKey: string;
thirdKey: string;
}
let someObject: ISomeObject = {
firstKey: 'firstValue',
secondKey: 'secondValue',
thirdKey: 'thirdValue'
};
let key: string = 'secondKey';
let secondValue: string = someObject[key];
Należy zauważyć, że idea polega na tym, że zmienna klucza pochodzi z innego miejsca w aplikacji i może być dowolnym kluczem w obiekcie.
Próbowałem jawnie rzutować ten typ przez:
let secondValue: string = <string>someObject[key];
A może mój scenariusz jest po prostu niemożliwy --noImplicitAny
?
źródło
Innym sposobem uniknięcia błędu jest użycie takiej obsady:
let secondValue: string = (<any>someObject)[key];
(Uwaga w nawiasie)Jedynym problemem jest to, że nie jest to już bezpieczne dla typu, jak rzucasz
any
. Ale zawsze możesz przywrócić właściwy typ.ps: używam maszynopisu 1.7, nie jestem pewien co do poprzednich wersji.
źródło
let secondValue: string = (someObject as any)[key];
TypeScript 2.1 wprowadził elegancki sposób obsługi tego problemu.
Możemy uzyskać dostęp do wszystkich nazw właściwości obiektów podczas fazy kompilacji według
keyof
słowa kluczowego (patrz dziennik zmian ).Trzeba tylko zastąpić
string
typ zmiennejkeyof ISomeObject
. Teraz kompilator wie, żekey
zmienna może zawierać tylko nazwy właściwości zISomeObject
.Pełny przykład:
Kod aktywny na typescriptlang.org (ustaw
noImplicitAny
opcję)Dalsza lektura przy większej liczbie
keyof
zastosowań .źródło
key
jakoconst key = (keyof ISomeObject)
= „drugi” + „Klucz”Poniższe ustawienie tsconfig pozwoli ci zignorować te błędy - ustaw na true.
źródło
--noImplicitAny
. Dopasuj idealnie op.XMLHttpRequest
.keyof
Operator TS2.1 może pomóc zachować wszystko w ścisłej zgodności, patrz odpowiedź Piotra!Wspomniane wyżej rozwiązanie „keyof” działa. Ale jeśli zmienna zostanie użyta tylko raz, np. W wyniku zapętlenia obiektu itp., Można go także rzutować.
źródło
posługiwać się
keyof typeof
źródło
Podobne do odpowiedzi @Piotra Lewandowskiego, ale w
forEach
:źródło
Argument of type '(field: "id" | "url" | "name") => void' is not assignable to parameter of type '(value: string, index: number, array: string[]) => void'
. Mój kod wygląda takObject.keys(components).forEach((comp: Component) => {...}
, gdzieComponent
jest typ (jakMyConfig
).Zadeklaruj obiekt w ten sposób.
źródło
Nie masz indeksatora? Następnie stwórz własny!
Globalnie zdefiniowałem to jako łatwy sposób zdefiniowania podpisu obiektu.
T
może być wany
razie potrzeby:Po prostu dodaję
indexer
jako członek klasy.Skończyłem z tym:
Zaletą tego jest to, że odzyskujesz właściwy typ - wiele używanych rozwiązań
<any>
utraci dla Ciebie pisanie. Pamiętaj, że nie wykonuje to żadnej weryfikacji środowiska wykonawczego. Nadal musisz sprawdzić, czy coś istnieje, jeśli nie wiesz na pewno.Jeśli chcesz być zbyt ostrożny i używasz tego,
strict
możesz to zrobić, aby odsłonić wszystkie miejsca, które mogą być potrzebne do wykonania jawnej, niezdefiniowanej kontroli:Zwykle nie uważam tego za konieczne, ponieważ skoro mam gdzieś właściwość ciągu, zwykle wiem, że jest poprawna.
Uważam tę metodę za szczególnie przydatną, jeśli mam dużo kodu, który musi uzyskać dostęp do indeksu, a pisanie można zmienić w jednym miejscu.
Uwaga: Używam
strict
trybu iunknown
jest to zdecydowanie konieczne.Skompilowany kod będzie po prostu
indexer = this
, więc jest bardzo podobny do tego, kiedy tworzy się_this = this
dla Ciebie maszynopis .źródło
Record<T>
zamiast tego użyć tekstu - nie jestem teraz w stanie zbadać dokładnych szczegółów tego, ale w niektórych ograniczonych przypadkach może to działać lepiej.Utwórz interfejs, aby zdefiniować interfejs „indeksatora”
Następnie utwórz obiekt z tym indeksem.
Uwaga: nadal będą występować te same problemy, które opisały inne odpowiedzi dotyczące egzekwowania typu każdego elementu - ale często tego właśnie chcesz.
Możesz ustawić parametr typu ogólnego, cokolwiek potrzebujesz:
ObjectIndexer< Dog | Cat>
Plac zabaw dla maszynopisu
Możesz nawet użyć tego w ograniczeniu ogólnym podczas definiowania typu ogólnego:
export class SmartFormGroup<T extends IndexableObject<any>> extends FormGroup
Następnie
T
wewnątrz klasy można indeksować :-)źródło
Dictionary
reprezentowania tego{ [key: string]: T }
, ale jeśli kiedykolwiek istnieje, edytuj to pytanie, aby usunąć mojeObjectIndexer
.Zadeklaruj typ, którego kluczem jest łańcuch i wartością może być dowolny, a następnie zadeklaruj obiekt za pomocą tego typu, a włókna nie będą się wyświetlać
Twój kod będzie
źródło
Obecnie lepszym rozwiązaniem jest deklarowanie typów. Lubić
źródło
Najprostszym rozwiązaniem, które można znaleźć za pomocą Typescript 3.1 w 3 krokach, jest:
1) Utwórz interfejs
2) Wykonaj kopię na maszynie
3) Używaj w dowolnym miejscu (w zestawie JSX)
źródło