έλεγχος τύπων - Η Typescript αποτυγχάνει να ελέγξει την εμφωλευμένη αντικείμενο στον τύπο επιστροφής της συνάρτησης
Το Typescript δεν ελέγχει τον τύπο επιστροφής αν είναι μια εμφωλευμένη αντικείμενο. Σκεφτείτε τον κώδικα παρακάτω, το Typescript δεν θα στείλει σφάλματα ακόμα κι αν η μεταβλητή result στη συνάρτηση A δεν αντιστοιχεί σαφώς στον τύπο Output.
interface Input {
a: string;
b: number;
}
interface Output {
c: Omit<Input, 'a'>;
d: string;
}
function A(input: Input): Output {
const result = { c: {a: 'aaa', b: 3}, d: 'okay' };
// Expect to have an error since the result is not matched to Output
// but there's not errors
return result;
}
function B(input: Input): Output {
const result = "{ c: {a: 'aaa', b: 3}, d: 'okay' }";
// Work as expected
return result;
}
// But access a property will give us error.
const test = A({ a: 'a', b: 3 });
test.c.a
Παιδική χαρά εδώ.
Κάποια ιδέα γιατί συνέβη αυτό;
Αν πούμε ρητά στο Typescript ότι const result: Output=..., θα μας δώσει σφάλματα. Αλλά δεν είμαι σίγουρος αν αυτή είναι καλή πρακτική ή όχι. Υπάρχει άλλος τρόπος να το κάνουμε να λειτουργεί όπως αναμένεται;
Απάντηση #1
Κάποια ιδέα γιατί συνέβη αυτό;
Αν δηλώναμε ρητά στο Typescript ότι
const result: Output=..., θα μας έδινε σφάλματα....
Το TypeScript εφαρμόζει πιο αυστηρό έλεγχο τύπων στα αντικείμενα λεκτικά απ' ό,τι σε άλλες εκφράσεις (συμπεριλαμβανομένων των αναφορών σε μεταβλητές). Σε αυτήν την περίπτωση, το "πιο αυστηρό" μέρος όταν παρέχετε ρητά έναν τύπο για το result είναι ένας έλεγχος υπερβάλλοντων ιδιοτήτων.¹ Αυτός είναι ένας πρακτικός έλεγχος που γίνεται επειδή συνήθως είναι σφάλμα προγραμματιστή, αλλά στην γενική περίπτωση οι υπερβάλλουσες ιδιότητες είναι αποδεκτές (επειδή το σχήμα του αντικειμένου εξακολουθεί να ταιριάζει με τον στόχο τύπο, απλώς είναι ένας υποτύπος επειδή έχει περισσότερες ιδιότητες).
Λαμβάνετε επίσης το σφάλμα αν κάνετε την επιστροφή απευθείας:
function A(input: Input): Output {
return { c: {a: 'aaa', b: 3}, d: 'okay' };
}
αν και (υποκειμενικά) γενικά προτιμώ τον αρχικό σου κώδικα γιατί είναι πιο εύκολος στο εντοπισμό σφαλμάτων.
Εξαρτάται σε μεγάλο βαθμό από το στυλ, αλλά θα έλυνα το πρόβλημα κάνοντας αυτό ως γενική πρακτική όταν είναι δυνατό:
function A(input: Input) {
// ^−−−− No return type annotation
const result: Output = { c: {a: 'aaa', b: 3}, d: 'okay' };
// ^−−−−−−−−−− Explicit type
return result; // <−−−−−− TypeScript infers return type
}
Σημειώστε ότι ο τύπος επιστροφής της συνάρτησης είναι ακόμα Output, απλώς η TypeScript τον υποθέτει από το return αντί να τον καθορίσουμε ρητά σε δύο σημεία.
Σύνδεσμος παιδικής χαράς
¹ Καθώς γράφω αυτό τον Απρίλιο του 2021, η τεκμηρίωση του TypeScript περνάει από μια σημαντική αναθεώρηση, και η συνδεδεμένη σελίδα αναφέρεται ως «καταργημένη» με νέα σύνδεση προς «τη νέα σελίδα», αλλά η νέα σελίδα δεν περιγράφει ακόμη τους ελέγχους υπερβολικών ιδιοτήτων. Ελπίζουμε ότι αυτό θα διορθωθεί σύντομα.
