Skip to content

Instantly share code, notes, and snippets.

@jfet97
Last active May 10, 2022 20:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jfet97/b36333f089dba6cce01d54b6de196236 to your computer and use it in GitHub Desktop.
Save jfet97/b36333f089dba6cce01d54b6de196236 to your computer and use it in GitHub Desktop.
types for string long exact/at least/at most n chars
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y
? 1
: 2
? true
: false;
interface StringCostrainType {
readonly _N: number;
readonly _E: unknown;
readonly _type: "exact" | "atleast" | "atmost";
}
export interface Exact<N extends number, E = never> extends StringCostrainType {
readonly _N: N;
readonly _E: E;
readonly _type: "exact";
}
export interface AtLeast<N extends number, E = never>
extends StringCostrainType {
readonly _N: N;
readonly _E: E;
readonly _type: "atleast";
}
export interface AtMost<N extends number, E = never>
extends StringCostrainType {
readonly _N: N;
readonly _E: E;
readonly _type: "atmost";
}
type SameLenTuple<N extends number, _R extends any[] = []> = Equal<
N,
_R["length"]
> extends true
? _R
: SameLenTuple<N, [0, ..._R]>;
// false if same length or shorter
type IsLonger<F extends any[], S extends any[]> = F extends [
infer FHEAD,
...infer FREST
]
? S extends [infer SHEAD, ...infer SREST]
? IsLonger<FREST, SREST>
: true
: false;
type ExactChecker<
SCT extends Exact<number, any>,
S extends string,
_R extends any[] = [],
_S = S
> = S extends `${infer C}${infer REST}`
? ExactChecker<SCT, REST, [..._R, C], _S>
: Equal<SCT["_N"], _R["length"]> extends true
? _S
: SCT["_E"];
type AtLeastChecker<
SCT extends AtLeast<number, any>,
S extends string,
_R extends any[] = [],
_S = S
> = S extends `${infer C}${infer REST}`
? AtLeastChecker<SCT, REST, [..._R, C], _S>
: IsLonger<SameLenTuple<SCT["_N"]>, _R> extends true
? SCT["_E"]
: _S;
type AtMostChecker<
SCT extends AtMost<number, any>,
S extends string,
_R extends any[] = [],
_S = S
> = S extends `${infer C}${infer REST}`
? AtMostChecker<SCT, REST, [..._R, C], _S>
: Equal<SCT["_N"], _R["length"]> extends true
? _S
: IsLonger<SameLenTuple<SCT["_N"]>, _R> extends true
? _S
: SCT["_E"];
export type Checker<
SCT extends StringCostrainType,
S extends string
> = SCT extends Exact<number, any>
? ExactChecker<SCT, S>
: SCT extends AtLeast<number, any>
? AtLeastChecker<SCT, S>
: SCT extends AtMost<number, any>
? AtMostChecker<SCT, S>
: never;
type test_exact_1 = Checker<Exact<3>, "cio">;
type test_exact_2 = Checker<Exact<3>, "ci">;
type test_exact_3 = Checker<Exact<3>, "ciao">;
type test_atleast_1 = Checker<AtLeast<3>, "cio">;
type test_atleast_2 = Checker<AtLeast<3, "at least 3 chars plz">, "ci">;
type test_atleast_2bis = Checker<AtLeast<3, "at least 3 chars plz">, string>;
type test_atleast_3 = Checker<AtLeast<3>, "ciao">;
type test_atmost_1 = Checker<AtMost<3>, "cio">;
type test_atmost_2 = Checker<AtMost<3>, "ci">;
type test_atmost_3 = Checker<AtMost<3>, "ciao">;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment