J'ai cette interface, qui stocke simplement une clé d'une autre interface (modelKey
) et la valeur de cette touche (value
):
interface ValueHolder<T, H extends keyof T> {
modelKey: H;
value: T[H];
}
Maintenant, je veux stocker le modèle horsePower
à partir du modèle suivant, avec le type correspondant dans un ValueHolder
:
interface Car {
id: number;
horsePower?: number;
date: Date;
};
Cela ressemble à ceci:
const test: ValueHolder<Car, keyof Car> = {
modelKey: 'horsePower',
value: 1000,
};
À ce stade, aucune erreur ne se produit et elle stockerait la valeur bien. Mais vous pouvez également passer une valeur de type Date
:
const test: ValueHolder<Car, keyof Car> = {
modelKey: 'horsePower',
value: new Date(),
};
Parce que pour une raison quelconque la valeur peut accepter tous les types de clé du modèle fourni:
(property) ValueHolder<Car, keyof Car>.value: string | number | Date | undefined
Comment puis-je créer la clé value
de l'interface ValueHolder
n'accepte que des valeurs de type undefined | number
, si vous fournissez le modelKey
_ _ horsePower
?
ValueHolder
Argument générique H
permet à toutes les clés qui conduisent à toutes les valeurs.
Vous devez modifier légèrement votre type d'utilité principal pour rendre l'état illégal non représentable.
Considérez cet exemple:
type Values<T> = T[keyof T]
type ValueHolder<T> = Values<{
[Prop in keyof T]: {
modelKey: Prop;
value: T[Prop]
}
}>
// type Test = {
// modelKey: "id";
// value: number;
// } | {
// modelKey: "horsePower";
// value: number | undefined;
// } | {
// modelKey: "date";
// value: Date;
// } | undefined
type Test = ValueHolder<Car>
interface Car {
id: number;
horsePower?: number;
date: Date;
};
// ok
const test: ValueHolder<Car> = {
modelKey: 'horsePower',
value: 1000,
};
// error
const test2: ValueHolder<Car> = {
modelKey: 'horsePower',
value: new Date(),
};
Voir type Test
. ValueHolder
crée une union de toutes les valeurs autorisées. Il iTère à travers chaque clé et crée cette interface {Prop: {Modelkey: p, valeur: t [p]}}. Alors Values
obtient chaque valeur d'objet {modelKey:P, value:T[P]}
et fait une union d'entre eux.
[~ # ~ ~] Mise à jour [~ # ~]
Merci, fonctionne bien! Et si je veux ça
T[Prop]
ne peut être que de la chaîne de type? Est-ce aussi possible?
Oui c'est le cas. Il y a deux façons de le réaliser. Vous pouvez autoriser ValueHolder
uniquement pour recevoir des objets où les valeurs sont des chaînes.
type ValueHolder<T extends Record<string, string>> = Values<{
[Prop in keyof T]: {
modelKey: Prop;
value: T[Prop]
}
}>
Ou, vous pouvez vérifier à l'intérieur de l'itération si T[Prop]
est une chaîne ou non.
type ValueHolder<T> = Values<{
[Prop in keyof T]: T[Prop] extends string ? {
modelKey: Prop;
value: T[Prop]
} : never
}>