admin管理员组

文章数量:1289830

I am attempting to write a type that applies the pluralize library to a string. The purpose of this is to take a list of strings that contains my database tables, and convert them to the pluralized version, as that is how relations are defined in my schema (Ex: Student -> Students).

I am an utter novice to writing types, and Google AI gave me the naive solution:

type Pluralize<T extends string> = T extends `${infer S}sis`
    ? `${S}ses`
    : T extends `${infer S}y`
    ? `${S}ies`
    : T extends `${infer S}s`
    ? T
    : `${T}s`;

This solution works, but it fails to properly convert words like "day" to "days", and instead converts it to "daies". I could in theory add more rules to make it robust, but that seems like reinventing the wheel.

I want to write a type that, instead of simply replacing the ending, applies a function to the string. I attempted the solution:

import pluralize from "pluralize";

type Pluralize<T extends string> = T extends string ? pluralize(T) : never;

This solution is wrong, but I'm not well-versed in Typescript and I'm not sure how to fix it. Any advice on a direction to go would be greatly appreciated.

I am attempting to write a type that applies the pluralize library to a string. The purpose of this is to take a list of strings that contains my database tables, and convert them to the pluralized version, as that is how relations are defined in my schema (Ex: Student -> Students).

I am an utter novice to writing types, and Google AI gave me the naive solution:

type Pluralize<T extends string> = T extends `${infer S}sis`
    ? `${S}ses`
    : T extends `${infer S}y`
    ? `${S}ies`
    : T extends `${infer S}s`
    ? T
    : `${T}s`;

This solution works, but it fails to properly convert words like "day" to "days", and instead converts it to "daies". I could in theory add more rules to make it robust, but that seems like reinventing the wheel.

I want to write a type that, instead of simply replacing the ending, applies a function to the string. I attempted the solution:

import pluralize from "pluralize";

type Pluralize<T extends string> = T extends string ? pluralize(T) : never;

This solution is wrong, but I'm not well-versed in Typescript and I'm not sure how to fix it. Any advice on a direction to go would be greatly appreciated.

Share Improve this question asked Feb 19 at 20:05 Zenith2198Zenith2198 651 silver badge9 bronze badges 5
  • 4 At first, try to ask yourself "why do I need to have a strict types for the list of plural strings instead of just having string[]". What benifit will you get from that type? – Andrei Khotko Commented Feb 19 at 20:21
  • The benefit is clarity in the code, specifically what the argument is meant to be. It is strictly meant to be the pluralized version of one out of a list of a few strings. This would accurately represent that. – Zenith2198 Commented Feb 19 at 20:38
  • 1 TypeScript's type-level syntax is not itself JavaScript, and you cannot use JavaScript functions at the type level. You'd need something like ms/TS#41577 at a minimum, which is unlikely to happen anytime soon (too many questions about how it would behave) and even then it wouldn't let you just import some JS stuff as TS types. The answer to the question in the title is therefore: this is not possible unless you write the "function" as some kind of conditional or lookup type. – jcalz Commented Feb 19 at 20:56
  • It not being possible is a helpful answer, thank you! – Zenith2198 Commented Feb 19 at 21:09
  • Okay I’ll write that up then. – jcalz Commented Feb 19 at 21:50
Add a comment  | 

1 Answer 1

Reset to default 3

If by "function" you specifically mean a JavaScript function, then this is impossible in TypeScript. JavaScript code runs at runtime, and JavaScript code cannot simply be "lifted" to the type level to run at compile time. TypeScript's type syntax is effectively a different, largely declarative language, and to the extent that it resembles JavaScript, it's because they are usually analogous to each other, but not the same. You can write const x = 5; and type X = 5;, but there's no type X = 2 + 3; or type X = Math.sqrt(25) or anything like that. As a declarative language there's little sense of control flow as you'd find in an imperative language like JavaScript. There's nothing like if (X < Y) { type Z = 1; } or while (X < 10) { type X = X + 1 }. There are recursive conditional types, but these are more analogous to recursive functional programming implementations than JavaScript. So no matter what, you cannot take some JavaScript library and import its runtime functions into the type level, and then use it in a function.

There is a longstanding open feature request at microsoft/TypeScript#41577 to allow people to write "functions" to define types. It's not clear how that could be implemented. TypeScript has a lot of features and moving parts, and any addition would have to play nicely with them.

For example, there's type inference. You can write type X<T> = {x: T} and then declare function f<T>(x: X<T>): T and then call f({x: "abc"}) and TypeScript can infer that T must be string for that call. Meaning it looks at {x: "abc"}, and at the definition of X<T>, and figures out what T should have been for that to match up. It's like running a function backwards. Inference isn't perfect, but if people started adding arbitrary type functions, they'd have to at least think about inference.

And types aren't one-to-one mappings to values, they are more like one-to-many. So you'd have to decide what your type does, for example, with unions and intersections. Does it distribute across them somehow? What about optional properties? Etc etc etc.


Anyway, even if they did implement it, it's quite unlikely it would be something where you could just import some runtime library. At best it would be some more ergonomic way to write declarative types in a more imperative "style". But this is pure speculation. Suffice it to say that this is currently impossible.

If you want some kind of type system behavior, you'll have to write it in the type system. That will look like indexed accesses or conditional types, and they can be very complex and have edge cases.

本文标签: javascriptHow to write a Typescript type that applies a function to a stringStack Overflow