最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - TypeScript lowercase string - Stack Overflow

programmeradmin1浏览0评论

Is there a way to make sure that TS will scream if it receives something else from lowercase string for fieldName?

type Props = {
  onEdit: (data: Record<string, string | number>) => void;
  title: string;
  fields: {
    fieldName: string;
    fieldValue?: string | number;
   }
};

Is there a way to make sure that TS will scream if it receives something else from lowercase string for fieldName?

type Props = {
  onEdit: (data: Record<string, string | number>) => void;
  title: string;
  fields: {
    fieldName: string;
    fieldValue?: string | number;
   }
};
Share Improve this question edited Jan 26, 2022 at 13:44 Tasos Tsournos asked Jan 26, 2022 at 13:40 Tasos TsournosTasos Tsournos 3833 silver badges10 bronze badges 5
  • 1 Probably not since "lowercase" isn't a type. --- That being said, there does seem to be a thing called "refinement types"? lemoine-benoit.medium./… – evolutionxbox Commented Jan 26, 2022 at 13:43
  • in typescript 4.1+ you can tediously make an interface that only has lowercase letters in | , documentation here : typescriptlang/docs/handbook/2/template-literal-types.html – tsamridh86 Commented Jan 26, 2022 at 13:50
  • 1 If that property is assigned anything other than a pile time constant, definitely impossible. A better question is why you need to encode that particular constraint in the type system? – Jared Smith Commented Jan 26, 2022 at 13:50
  • 3 fieldName.toLowerCase() === fieldName. Or write 30 lines of overkill typing nonsense. – morganney Commented Jan 26, 2022 at 13:52
  • 2 To further what @morganney says, your TS code will be Javascript at runtime, and possibly have to interface with non-TS JS code as well. Types are nice, but in addition to the hit to readability you are to some degree tilting with windmills if you attempt to do too much in TS's type system. Don't let it lull you into a false sense of security about runtime checks on invariants. – Jared Smith Commented Jan 26, 2022 at 13:53
Add a ment  | 

2 Answers 2

Reset to default 4

It's simple enough to create a utility to enforce that string literals are lowercase using the type utility Lowercase<StringType>:

TS Playground

type EnforceLowerCase<T extends string> = Lowercase<T> extends T ?
  string extends T ? never : T
  : never;
  
type Str1 = EnforceLowerCase<'Hello'>; // never
type Str2 = EnforceLowerCase<'hello'>; // "hello"

However, using it in your scenario would be very convoluted, because it would require using only string literals (which TS doesn't infer on object property values).


Instead, it's better to ensure conformance of the expectation at runtime. Here's an example using a pure function which doesn't mutate the input object:

TS Playground

function ensureLowerCaseFieldName (props: Props): Props {
  return {...props, fields: {
    ...props.fields,
    fieldName: props.fields.fieldName.toLocaleLowerCase(),
  }};
}

function doSomethingWithProps (props: Props) {
 props = ensureLowerCaseFieldName(props);
 console.log(props);
}

const props: Props = {
  onEdit: data => {},
  title: 'title',
  fields: {fieldName: 'Hello'},
};

doSomethingWithProps(props); // {..., fields: { fieldName: "hello" } }

As of TypeScript 4.8 there is now support for using the intrinsic string manipulation types with wide types like string. This was implemented in microsoft/TypeScript#47050 but not mentioned in the TS 4.8 release notes.

So now, Lowercase<string> only corresponds to lowercase strings (strings which remain unchanged after .toLowerCase()), whereas in TypeScript 4.7 and below it could match any string:

type Props = {
    onEdit: (data: Record<string, string | number>) => void;
    title: string;
    fields: {
        fieldName: Lowercase<string>;
        fieldValue?: string | number;
    }
};

const p: Props = {
    onEdit() { },
    title: "ABC",
    fields: {
        fieldName: "okay"  // okay      
    }
}
p.fields.fieldName = "Oops" // error! Type 'string' is not assignable to type 'Lowercase<string>'
p.fields.fieldName = "123" // okay, Lowercase<"123"> is "123"

Playground link to code

发布评论

评论列表(0)

  1. 暂无评论