You can define primitive type aliases (e.g. string identifiers) in TypeScript that prevent you from using the wrong type using unique symbols.
This doesn't work if you only define the aliases. For example:
type userId = string;
type projectId = string;
const myUserId: userId = "u001";
// This looks like it should give you a warning, but it doesn't.
const myProjectId: projectId = myUserId;
type projectId = string;
const myUserId: userId = "u001";
// This looks like it should give you a warning, but it doesn't.
const myProjectId: projectId = myUserId;
This can be solved by defining your types like this:
type userId = string & {readonly id: unique symbol};
type projectId = string & {readonly id: unique symbol};
// A string can't just be assigned as a userId anymore, but this works.
const myUserId: userId = "u001" as userId;
// TS2322: Type 'userId' is not assignable to type 'projectId'. ๐
const myProjectId: projectId = myUserId;
type projectId = string & {readonly id: unique symbol};
// A string can't just be assigned as a userId anymore, but this works.
const myUserId: userId = "u001" as userId;
// TS2322: Type 'userId' is not assignable to type 'projectId'. ๐
const myProjectId: projectId = myUserId;