Skip to content

Commit

Permalink
📌 v0.2.0 Fix nominal for newer versions of typescript
Browse files Browse the repository at this point in the history
- Breaking Change: Remove nominal and nominal.make
- Use simpler implementation from #1 credit to @MananTank as this solves the "error TS2527: The inferred type of 'nominal' references an inaccessible 'unique symbol' type. A type annotation is necessary."
  • Loading branch information
CryogenicPlanet committed Mar 22, 2023
1 parent bf7f8c1 commit 00faaf1
Show file tree
Hide file tree
Showing 6 changed files with 19 additions and 56 deletions.
4 changes: 2 additions & 2 deletions examples/basic.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// After Nominal
import { Nominal, nominal } from '../src';
import { Nominal } from '../src';
import { Equal, Expect } from '@type-challenges/utils';

type Minutes = Nominal<'Minutes', number>;
Expand All @@ -9,7 +9,7 @@ const minutesToSeconds = (minutes: Minutes): Seconds =>
(minutes * 60) as Seconds;

// You can directly type cast or use nominal.make
const seconds = nominal.make<Seconds>(420);
const seconds = 420 as Seconds;
const minutes = 1337 as Minutes;

// @ts-expect-error - doesn't work, yay type safety
Expand Down
3 changes: 3 additions & 0 deletions examples/safeRecord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ const add = <V, R extends string, R2 extends string>(

const safeRecord = newRecord('a', 'b');

// @ts-expect-error - Won't work
const x = safeRecord['random']; // any

const lmao = add(safeRecord, 'lmao', 'nice');

lmao.a; // string
lmao.lmao; // string

// @ts-expect-error - Won't work
lmao['random']; // any - Untyped
5 changes: 3 additions & 2 deletions examples/sort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const binarySearch = <T>(
return midPoint;
}

if (search > sorted[midPoint]) {
// Bang: Midpoint will exist
if (search > sorted[midPoint]!) {
return binarySearch(sorted.slice(midPoint) as SortedArray<T>, search);
} else {
return binarySearch(sorted.slice(0, midPoint) as SortedArray<T>, search);
Expand All @@ -25,7 +26,7 @@ const binarySearch = <T>(
};

const regularArray = [1, 7, 2, 3, 6, 9, 10, 4, 5];
// won't work
// @ts-expect-error won't work
binarySearch(regularArray, 2);
// will work
binarySearch(sort(regularArray), 2);
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nominal-types",
"version": "0.1.4",
"version": "0.2.0",
"description": "Nominal types for better typesafety",
"main": "src/index.ts",
"types": "src/index.ts",
Expand All @@ -18,6 +18,6 @@
"devDependencies": {
"@type-challenges/utils": "^0.1.1",
"rome": "^10.0.1",
"typescript": "^4.7.4"
"typescript": "^5.0.2"
}
}
12 changes: 6 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 3 additions & 44 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,7 @@
class NominalWrapper<Name extends string, Type> {
nominal = () => {
const NewSymbol = Symbol('');
const M = Symbol();

type NominalType<N extends string | never, T> = T & {
readonly /**
* @deprecated Do not use this it may not exist in runtime, this is only for typechecking purpose
*/
[key in N]: typeof NewSymbol;
};

return {} as NominalType<Name, Type>;
};
}

export type Nominal<Name extends string, Type> = ReturnType<
NominalWrapper<Name, Type>['nominal']
>;

type InternalInferPrimitive<T> = T extends {}
? {
[K in keyof T]: isSymbol<T[K]> extends true ? never : T[K];
}
: undefined;

type InferPrimitive<T> = T extends {}
? OmitNever<InternalInferPrimitive<T>>
: T;
// type InferPrimitive2<T> = T extends Nominal<string, any> ? Name : undefined;

type isSymbol<T> = T extends symbol ? true : false;

type Values<T> = T[keyof T];

type OmitNever<T> = Pick<
T,
Values<{
[Prop in keyof T]: [T[Prop]] extends [never] ? never : Prop;
}>
>;

const make = <T>(value: InferPrimitive<T>) => value as T;

export const nominal = {
make,
export type Nominal<Name extends string, Type> = Type & {
readonly [M]: [Name];
};

export * from './standardLib';
Expand Down

0 comments on commit 00faaf1

Please sign in to comment.