I would like to constrain the a generic parameter T
of a class MyClass<T>
such that T
is valid for any record which has only 1 key:
type ValidShape = {
key: any;
};
type InvalidShape = {
key1: any;
key2: any;
};
class MyClass<T ...> {
//...
};
const valid = new MyClass<ValidShape>() // ok
const invalid = new MyClass<InvalidShape>() // should not compile, ideally.
I was instead able to define a type which is constrained to being a string literal and not a union, based on a previous answer
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
type StringLiteral<T extends string> = [T] extends [UnionToIntersection<T>]
? string extends T ? never : T : never;
With these types, I am able to construct a class which accepts only a string literal K
that is also not a union of string literals. With K
constrained, Record<K, any>
contains a single key:
class MyClass<K extends [K] extends [StringLiteral<K>] ? string : never> {
constructor() {};
functionThatMeetsMyGoal(arg: Record<K, any>) : Record<K, any> {}
};
let t = new MyClass<"a">(); // Ok: Valid
let u = new MyClass<"a" | "b">(); // Ok: Invalid `"a" | "b"` does not satisfy `never`
let v = new MyClass<string>(); // Ok: Invalid `string` does not satisfy `never`
let w = new MyClass<1>(); // Ok: Invalid `1` does not extend `string`
let x = new MyClass<never>(); // Not ok, but I can live with that...
I am satisfied with this approach; but since I am new to Typescript, and I am wondering if there was a simpler solution.
Currently using typescript 5.5.
sbgrl is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.