2015-11-05 18 views
10

Sto cercando un modo per ottenere un nome di proprietà dell'oggetto con typechecking che consente di rilevare possibili regressioni dopo il refactoring.Modo sicuro per estrarre i nomi delle proprietà in TypeScript

Ecco un esempio: il componente in cui devo passare i nomi delle proprietà come stringhe e verrà interrotto se tenterò di modificare i nomi delle proprietà nel modello.

interface User { 
    name: string; 
    email: string; 
} 

class View extends React.Component<any, User> { 

    constructor() { 
     super(); 
     this.state = { name: "name", email: "email" }; 
    } 

    private onChange = (e: React.FormEvent) => { 
     let target = e.target as HTMLInputElement; 
     this.state[target.id] = target.value; 
     this.setState(this.state); 
    } 

    public render() { 
     return (
     <form> 
      <input 
       id={"name"} 
       value={this.state.name} 
       onChange={this.onChange}/> 
      <input 
       id={"email"} 
       value={this.state.email} 
       onChange={this.onChange}/> 
      <input type="submit" value="Send" /> 
     </form> 
    ); 
    } 
} 

Apprezzerei se c'è qualche soluzione piacevole per risolvere questo problema.

+1

Al momento non ci sono alcuni suggerimenti su GitHub per aiutare con questo (Vedi [# 1579] (https://github.com/Microsoft/TypeScript/issues/1579), [# 394] (https: //github.com/Microsoft/TypeScript/issues/394) e [# 1003] (https://github.com/Microsoft/TypeScript/issues/1003)). Puoi controllare [questo] (http://stackoverflow.com/a/32542368/188246), ma attenzione potrebbe non funzionare una volta che il codice è stato risolto. –

+0

@DavidSherret la tua soluzione "this" è l'unica risposta che posso fornire. Si prega di inviare come risposta – basarat

+0

@basarat lo farà, grazie! –

risposta

9

Nel TS 2.1 è stato introdotto, che la parola keyof reso possibile tutto questo:

const propertyOf = <TObj>(name: keyof TObj) => name; 

o

const propertyNamesOf = <TObj>() => (name: keyof TObj) => name; 

Questi possono quindi essere usato in questo modo:

propertyOf<MyObj>("myProperty"); 

o

const myObjProperties = propertyNamesOf<MyObj>(); 
myObjProperties("myProperty"); 

Questo vi darà un errore se myProperty non è una proprietà di tipo MyObj.

+0

Questo è grande. Ecco un esempio di come può essere aggiunto ad una classe https://gist.github.com/anonymous/5d5db4671480855070af478eb3fc2 –

16

Al momento non c'è davvero un ottimo modo per farlo, ma attualmente ci sono alcuni suggerimenti aperti su github (Vedi #1579, #394 e #1003).

Che cosa è possibile fare, è quanto mostrato in this answer -wrap che fa riferimento alla proprietà in una funzione, converte la funzione in una stringa, quindi estrae il nome della proprietà dalla stringa.

Ecco una funzione per farlo:

function getPropertyName(propertyFunction: Function) { 
    return /\.([^\.;]+);?\s*\}$/.exec(propertyFunction.toString())[1]; 
} 

quindi utilizzarlo in questo modo:

// nameProperty will hold "name" 
const nameProperty = getPropertyName(() => this.state.name); 

Questo potrebbe non funzionare a seconda di come il codice viene ridotte di così solo guardare fuori per questo.

Aggiornamento

E 'più sicuro per fare questo in fase di compilazione. Ho scritto ts-nameof quindi questo è possibile:

nameof<User>(s => s.name); 

compila a:

"name"; 
+0

per a => a.Proprietà Ho scoperto che avevo bisogno di rimuovere il '\}' dal regex –