Quando si esegue la Registrazione del compilatore (tsc
) per transpile Dattiloscritto codice eseguibile JavaScript, il linguaggio è di tipo statico, sistema viene cancellato. Così il vostro Foo
tipo (rinominato in maiuscolo per soddisfare TS convenzioni di denominazione) non è presente in nessuna forma in fase di runtime. Non c'è nulla che si può scorrere con la consegna delle chiavi go
e start
.
Il modo più semplice per ottenere qualcosa accada in fase di runtime è quello di scrivere il codice JavaScript necessario per farlo, e quindi assicurarsi che il Dattiloscritto compilatore è in grado di dare forti tipi di cui avete bisogno durante la scrittura. Questo è praticamente l' inverso di quello che stai cercando di fare.
Nel tuo caso: che cosa significa generate()
necessario per il lavoro in fase di esecuzione? Beh, se si può supporre che i valori generati dall' generate()
saranno gli oggetti che tiene solo string
valori di proprietà, quindi abbiamo bisogno di passare un elenco dei tasti di oggetto. Così che cosa se scriviamo generate()
per fare questo, e quindi definire Foo
in termini di output di generate()
invece di fare il contrario?
Per esempio:
function generate<K extends PropertyKey>(...keys: K[]) {
return Object.fromEntries(keys.map(k => [k, ""])) as { [P in K]: string };
}
const myFooObject = generate("go", "start");
type Foo = typeof myFooObject;
/* type Foo = {
go: string;
start: string;
} */
console.log(myFooObject)
/* {
"go": "",
"start": ""
} */
Qui generate()
è una generica funzione che prende una lista di chiavi (di tipo K
) e produce un valore di un tipo con le chiavi in K
e valori di tipo string
. Che {[P in K]: string}
è una mappata di tipo equivalente a Record<K, string>
utilizzando il Record<K, V>
tipo di utilità.
L'implementazione utilizza Object.fromEntries()
per creare l'oggetto, e il tipo di ritorno è affermato di essere il tipo giusto perché Dattiloscritto vede Object.fromEntries()
come la restituzione di un tipo che è troppo ampia per i nostri scopi.
Comunque quando si chiama const myFooObject = generate("go", "start")
, che genera un valore di tipo {go: string; start: string}
che è lo stesso del tuo Foo
tipo. Così si può definire Foo
come type Foo = typeof myFooObject
invece di farlo manualmente. Si potrebbe ancora farlo manualmente, ma il punto che vi sto mostrando è che è molto più facile scrivere un SECCO codice in Macchina, se si inizia con i valori e generare tipi da loro, invece di cercare di farlo in un altro modo.
Di nuovo, se si utilizza il Dattiloscritto del compilatore tsc
come-è, quindi digitare la cancellazione impedisce di scrivere generate()
dalla definizione di Foo
. Ma...
Se siete disposti ad aggiungere un passaggio di generazione per il vostro progetto e di eseguire la generazione di codice utilizzando il Dattiloscritto del compilatore API o qualcosa di simile, si può fare arbitrario cose con i tipi. Ci sono librerie che fanno cose simili a ciò che si desidera, ad esempio, ts-auto-mock crediti per generare gli oggetti mock dato un tipo di oggetto, che sembra esattamente il tuo caso d'uso.
Ad un extra di costruire passo potrebbe essere un approccio ragionevole per voi, ma se si va giù che il percorso dovrebbe notare che non stai usando semplicemente Dattiloscritto più (e quindi l'argomento è probabilmente fuori portata per una domanda con solo un Dattiloscritto tag).
Giochi link al codice