When dealing with multiple HTML forms, I need to set up inputs and manage their values. The structure of my types is as follows (you can paste it into TypeScript Playground http://www.typescriptlang.org/play to see it in action):
interface InputConfig {
readonly inputType: "text" | "password" | "list"
readonly attributes?: ReadonlyArray<string>
readonly cssClasses?: ReadonlyArray<string>
}
interface Inputs<T extends InputConfig | string | string[]> {
readonly username: (T & InputConfig) | (T & string)
readonly password: (T & InputConfig) | (T & string)
readonly passwordConfirmation: (T & InputConfig) | (T & string)
readonly firstname: (T & InputConfig) | (T & string)
readonly lastname: (T & InputConfig) | (T & string)
readonly hobbies: (T & InputConfig) | (T & string[])
}
type InputConfigs = Inputs<InputConfig> // case 1 (see below)
type InputValues = Inputs<string | string[]> // case 2 (see below)
const configs: InputConfigs = {
username: {
inputType: "text"
},
password: {
inputType: "password"
},
passwordConfirmation: {
inputType: "password"
},
firstname: {
inputType: "text"
},
lastname: {
inputType: "text"
},
hobbies: {
inputType: "list"
}
}
const values: InputValues = {
username: "testuser1",
password: "test1",
passwordConfirmation: "test1",
firstname: "Tester",
lastname: "1",
hobbies: ["a", "b", "c"]
}
const username: string = values.username
The key advantage of this generic method is the consistent field naming within the Inputs
interface: The names username
, password
, passwordConfirmation
,... are used by both InputConfigs
and InputValues
, making renaming very simple.
However, there is an issue with the last assignment
not being accepted by the compiler:const username: string = values.username
Type 'string | (string & InputConfig) | (string[] & InputConfig) | (string[] & string)' is not assignable to type 'string'.
Type 'string[] & InputConfig' is not assignable to type 'string'.
I expected it to work because my understanding was:
- case 1:
T
isInputConfig
and thereforeusername
is of typeInputConfig
because:T & InputConfig
=InputConfig & InputConfig
=InputConfig
T & string
=InputConfig & string
= nothing
- case 2:
T
isstring | string[]
and thususername
is of typestring
because:T & InputConfig
=
= nothing(string | string[]) & InputConfig
T & string
=(string | string[]) & string
=string