Задать вопрос
liaFcipE
@liaFcipE

Почему TS некорректно вычисляет тип?

typescript@5.2.2

tsconfig

{
  "compilerOptions": {
    "strict": true,
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "jsx": "preserve",
    "jsxImportSource": "solid-js",
    "types": ["vite/client", "node"],
    "noEmit": true,
    "isolatedModules": true
  }
}



Код:
const normalizeRules: (string | RegExp)[] = [/<[^>]*>?/gm, "&gt;", "&lt;"];
const normalizeByRules = (input: string) => normalizeRules.reduce((acc, rule) => acc.replaceAll(rule, ""), input);


В IDE ошибка будет выглядеть так:

651708aedb1fa419918491.png

Текстовый вариант ошибки:
TS2339: Property  replaceAll  does not exist on type  string | RegExp 
Property  replaceAll  does not exist on type  RegExp


Если же, я явно опишу тип аккумулирующего значения как string - все ок:

const normalizeRules: (string | RegExp)[] = [/<[^>]*>?/gm, "&gt;", "&lt;"];
const normalizeByRules = (input: string) => normalizeRules.reduce((acc: string  /* here */, rule) => acc.replaceAll(rule, ""), input);


Вопрос простой - почему? Ведь изначальное значение reduce - строка, почему он решает, что acc может стать RegExp?
  • Вопрос задан
  • 145 просмотров
Подписаться 1 Средний 4 комментария
Решения вопроса 1
WblCHA
@WblCHA
Потому что у редьюса 3 оверлоада:
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T;
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T;
reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U;

Если передаёшь инишиалВелью, то актуальны 2ой и 3ий. Если ты не передаёшь дженерик или не типизируешь аккумулятор, какой из оверлоадов "сработает" раньше, при условии, что тип инишиалВелью является частью типа велью?

normalizeRules.reduce((acc: string, rule) => acc.replaceAll(rule, ""), input);
// or
normalizeRules.reduce<string>((acc, rule) => acc.replaceAll(rule, ""), input);
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
emekhanikov
@emekhanikov
Разработчик и архитектор программного обеспечения
Думаю от того что аккумулятор того же типа что и значения в массиве (string | RegExp)
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T;
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы