type
just introduces a type alias for another type. In your case both Ref<Blog>
and Ref<User>
are really the same type string
and thus they are fully compatible.
You could use branded types, which use the way typescript determines type compatibility (structural compatibility) to make differently branded strings
(or any type really) incompatible:
class Blog {
id: string & { brand: 'blog' }
}
class User {
id: string & { brand: 'user' }
}
type Ref<T extends {id: string}> = T['id']
function createUserId(id: string) : Ref<User> {
return id as any
}
function createBlogId(id: string) : Ref<Blog> {
return id as any
}
let refBlog: Ref<Blog> = createBlogId("1");
let refUser: Ref<User> = createUserId("1");
refBlog = refUser // error
You need to define helper functions to create instances of the types or use casting, but the types will be incompatible.
This article has a bit more of a discussion on the topic. Also the typescript compiler uses this approach for paths
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…