Using the types defined here as an example we can create a conditional type where if the field is required field
type will be of type { required : true }
or {}
otherwise:
type DomainDefinition<F, M> = {
fields?: {
[K in keyof F]: ({} extends { [P in K]: F[K] } ? {} : { required: true }) & {} // Intersect with other properties as necessary
},
methods?: { [K in keyof M]: M[K] & Function },
}
type User = {
id: string,
name?: string
}
function createDomain<T>(o: DomainDefinition<T, any>) {
return o;
}
export const User = createDomain<User>({
fields: {
id: { required: true },
name: {},
},
});
Note This will test for optionality (the ?
modifier) it will not test for nullability ( | null | undefined
) depending on your use case this may or may not be important.
Also of interest may be this answer that has a test for the readonly
modifier. Using it, you can also add a isReadonly
field:
type IfEquals<X, Y, A, B> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? A : B;
type DomainDefinition<F, M> = {
fields?: {
[K in keyof F]:
({} extends { [P in K]: F[P] } ? {} : { required: true })
& IfEquals<{ [P in K]: F[P] }, { -readonly [P in K]: F[P] }, {}, { isReadonly: true }>
},
methods?: { [K in keyof M]: M[K] & Function },
}
type User = {
id: string,
readonly name?: string
}
function createDomain<T>(o: DomainDefinition<T, any>) {
return o;
}
export const User = createDomain<User>({
fields: {
id: { required: true },
name: { isReadonly: true },
},
});
If you want to filter out some properties, for example functions, you would have to replace all occurrences of F
with a filtered F
. To make it simpler just define an extra type alias:
type NonFunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T];
type DomainPropertyHelper<F> = {
[K in keyof F]: ({} extends { [P in K]: F[K] } ? {} : { required: true }) & {} // Intersect with other properties as necessary
};
type DomainDefinition<F, M> = {
fields?: DomainPropertyHelper<Pick<F, NonFunctionPropertyNames<F>>>,
methods?: { [K in keyof M]: M[K] & Function },
}