Right. I'm aware. My point was that even though the type system is powerful, somehow, I'm able to represent everything I need to in Kotlin's type system just fine and it feels a lot more type safe because it will throw a type error at runtime in the right place if I do a bad cast.
Typescript `as Foo` will not do anything at runtime, and it will just keep on going, then throw a type error somewhere else later (possibly across an async boundary).
You can, in theory use very strong lint rules (disallow `as` operator in favour of Zod, disallow postfix ! operator), but no actual codebase that I've worked on has these checks. Even the ones with the strictest checks enabled have gaps.
Not to mention, there's intentional unsoundness in the type system, so even if you wanted, you couldn't really create a save subset of TS.
Then there's the issue of reading the library types of some generic heavy code. When I "go to definition" in my fastify codebase, I see stuff like this
RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, Logger>
Which expands to this
export type RouteHandlerMethod<
RawServer extends RawServerBase = RawServerDefault,
RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
RawReply extends RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>,
RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
ContextConfig = ContextConfigDefault,
SchemaCompiler extends FastifySchema = FastifySchema,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
Logger extends FastifyBaseLogger = FastifyBaseLogger
> = (
this: FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>,
request: FastifyRequest<RouteGeneric, RawServer, RawRequest, SchemaCompiler, TypeProvider, ContextConfig, Logger>,
reply: FastifyReply<RouteGeneric, RawServer, RawRequest, RawReply, ContextConfig, SchemaCompiler, TypeProvider>
// This return type used to be a generic type argument. Due to TypeScript's inference of return types, this rendered returns unchecked.
) => ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric>
Other languages somehow don't need types this complicated and they're still safer at runtime :shrug: