преобразование числа в строку без расширения типа

#typescript #react-native

#typescript #react-native

Вопрос:

Я использую react native, и fontWeight значение стиля в тексте принимает следующее:

fontWeight?: "normal" | "bold" | "100" | "200" | "300" | "400" | "500" | "600" | "700" | "800" | "900";

У меня есть сторонний API, который возвращает FontWeight в виде числа. Этот API вернет следующее для FontWeight:

100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900

Я пытаюсь соединить эти два, но, похоже, не могу в этом разобраться. Выполнение

fontWeight: APIResult.fontWeight.toString(), выдает ошибку, поскольку в этот момент я передаю string , когда react native ожидает точное значение.

Комментарии:

1. Вы уверены, что это APIResult.fontWeight.toString() будет одним из "normal" | "bold" | "100" | "200" | "300" | "400" | "500" | "600" | "700" | "800" | "900" ? Или возможно, что этого не будет?

2. Я отредактировал свой вопрос, API возвращает 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900

3. Не могли бы вы вставить трассировку стека?

Ответ №1:

Вы думали о синтаксическом анализе из одного формата в другой? Это будет выглядеть следующим образом:

 type S = "normal" | "bold" | "100" | "200" | "300" | "400" | "500" | "600" | "700" | "800" | "900";
type N = 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;

type ParseFontWeightToString<T extends N> =
  T extends 100 ? '100' :
  T extends 200 ? '200' :
  T extends 300 ? '300' :
  T extends 400 ? '400' :
  T extends 500 ? '500' :
  T extends 600 ? '600' :
  T extends 700 ? '700' :
  T extends 800 ? '800' :
  T extends 900 ? '900' :
  never

type R = ParseFontWeightToString<700> // "700"
type R1 = ParseFontWeightToString<750> // ERROR
  

Это не красивый code hoverer, вы будете объявлять его только один раз.

<a rel="noreferrer noopener nofollow" href="https://www.typescriptlang.org/play/index.html#src=type S = "normal" | "bold" | "100" | "200" | "300" | "400" | "500" | "600" | "700" | "800" | "900";
type N = 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;

type ParseFontWeightToString =
T extends 100 ? ‘100’ :
T extends 200 ? ‘200’ :
T extends 300 ? ‘300’ :
T extends 400 ? ‘400’ :
T extends 500 ? ‘500’ :
T extends 600 ? ‘600’ :
T extends 700 ? ‘700’ :
T extends 800 ? ‘800’ :
T extends 900 ? ‘900’ :
never

type R = ParseFontWeightToString // «700»» rel=»nofollow noreferrer»>Игровая площадка

Ответ №2:

Самое простое (но не типобезопасное) решение — просто использовать утверждение типа

 type FontWeightAPIString = "100" | "200" | "300" | "400" | "500" |
  "600" | "700" | "800" | "900";

{ fontWeight: APIResult.fontWeight.toString() as FontWeightAPIString } 
  

или еще более простой (но еще менее безопасный)

 { fontWeight: APIResult.fontWeight.toString() as any } 
  

Другое возможное решение, если вы хотите попытаться помочь компилятору понять последствия вызова toString() :

 interface WeightMap {
    100: "100";
    200: "200";
    300: "300";
    400: "400";
    500: "500";
    600: "600";
    700: "700";
    800: "800";
    900: "900";
}
type WeightNumber<N extends keyof WeightMap = keyof WeightMap> = 
  { toString(this: number): WeightMap[N] } amp; N;

interface APIResult {
    fontWeight: WeightNumber; // was originally just 100 | 200 | ... | 800 | 900 ?
}

interface MyStyle {
    fontWeight?: "normal" | "bold" | "100" | "200" | "300" | "400" | 
      "500" | "600" | "700" | "800" | "900";
}

declare const apiResult: APIResult;
const foo: MyStyle = {
    fontWeight: apiResult.fontWeight.toString() // no error now
}
  

Здесь мы представили преобразование числовых весов в строковые веса как WeightMap и получили новый псевдоним типа с именем WeightNumber , который является подтипом number . WeightNumber Известно, что A является соответствующим объединением числовых литералов ( 100 | 200 | ... | 800 | 900 ), и у него есть явный toString() метод, который возвращает соответствующее объединение строковых литералов ( "100" | "200" | ... | "800" | "900" ). Вы также можете получить более конкретный тип, такой как WeightNumber<200> , если хотите.

Затем мы объявляем, что APIResult['fontWeight'] это WeightNumber .

Это позволяет компилятору сделать вывод, что возвращаемый тип APIResult['fontWeight']['toString'] соответствует fontWeight стилю и у вас нет ошибок.


Хорошо, надеюсь, это поможет. Удачи!