typescript - Αδύνατο να γίνει 'index type' χρησιμοποιώντας μια μεταβλητή τύπου string


Προσπαθώ να αντιστρέψω τα πεδία ενός αντικειμένου αν υπάρχει μια τιμή, αλλά λαμβάνω κάποιο σφάλμα που δεν μπορώ να αποκρυπτογραφήσω.

interface Control {
  name1: boolean;
  name2: boolean;
  ...
}

const values = ['name1', 'name2', ...];

const control: Control = {
  name1: false,
  name2: false,
  ...
}

for (const value of values) {
  if ((value in control) {
    control[value] = !control[value];  // error
  }
}

Μήνυμα σφάλματος:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Control'.
  No index signature with a parameter of type 'string' was found on type 'Control'.ts(7053)

Ωστόσο, το σφάλμα εξαφανίζεται αν περάσω ρητά ένα από τα πεδία του αντικειμένου, όπως control['name1']. Υπάρχει κάτι που δεν καταλαβαίνω;

Απάντηση #1

Η TypeScript δεν ξέρει ότι ο πίνακας values σας είναι ένας πίνακας συγκεκριμένων συμβολοσειρών, μόνο ότι είναι string[]. Δοκιμάστε το εξής:

interface Control {
  name1: boolean;
  name2: boolean;
}

const values = ['name1', 'name2'] as const;

const control: Control = {
  name1: false,
  name2: false,
}

for (const value of values) {
  if (value in control) {
    control[value] = !control[value];  // error
  }
}

Παιδική Χαρά TypeScript

Το as const λέει στο TypeScript να καθορίσει τον τύπο του values πιο αυστηρά ως ['name1', 'name2'] σε αυτή την περίπτωση, έτσι ώστε όταν το διατρέχετε, το value θα τύπτεται ως 'name1' | 'name2' και το TypeScript θα καταλάβει ότι αυτές οι τιμές μπορούν να χρησιμοποιηθούν για να δεικτοποιήσουν ένα Control.

Απάντηση #2

Η μεταβλητή value μπορεί να έχει οποιαδήποτε τιμή κατά τη διάρκεια εκτέλεσης της εφαρμογής και το TypeScript δεν έχει γνώση ότι είναι ένα έγκυρο κλειδί που ορίζεται μέσα στο αντικείμενο control. Επομένως, δεν μπορεί απλώς να συμπεράνει τον τύπο τιμής του control[value].

Η διόρθωση είναι όμως πολύ απλή, το μόνο που χρειάζεται να γίνει είναι να πούμε στο TypeScript ότι ο πίνακας values περιέχει μόνο έγκυρα κλειδιά από τον τύπο Control μέσω της χρήσης της σύνταξης keyof Control:

const values: (keyof Control)[] = ['name1', 'name2'];

Εδώ είναι ένας σύνδεσμος προς το Playground.