Tslint: конфликт правил 'no-inferrable-types' и 'typedef'

Созданный на 3 окт. 2015  ·  33Комментарии  ·  Источник: palantir/tslint

Привет еще раз,

Я не уверен, является ли это проблемой или дизайнерским решением, но я вижу конфликт между правилами no-inferrebale-types и typedef .

Бывший.

function fn(): void {
    for (let i = 0; i < 100; i++) {
        console.log(i);
    }
}

Фрагмент из https://github.com/palantir/tslint/blob/master/docs/sample.tslint.json :

 "typedef": [true, ...],
 "no-inferrable-types": true,

Когда у меня включены эти два правила, я получаю:

error (typedef) test.ts[2, 12]: expected variable-declaration: 'i' to have a typedef

Добавление аннотации типа number к переменной i вызывает, в свою очередь, следующую ошибку:

error (no-inferrable-types) test.ts[2, 14]: LHS type (number) inferred by RHS expression, remove type annotation

Есть ли способ, чтобы эти два правила сосуществовали друг с другом?

Например, я хочу иметь выводимые переменные, объявленные непосредственно с примитивным типом (как сказано в документе: number , boolean или string ), но, с другой стороны, я хочу для принудительного определения типов для непримитивных типов.

Спасибо,

О.

P1 Enhancement 🌹 R.I.P. 🌹

Самый полезный комментарий

:+1: В идеале (imo) я хотел бы сказать «всегда требуется typedef, если только тип не выводится». Что я не думаю, что сейчас возможно.

Все 33 Комментарий

Хороший улов, спасибо за наводку. Я добавил правило no-inferrable-types , не задумываясь о том, как оно может конфликтовать с правилом typedef , упс! На данный момент я бы рекомендовал отключить один из двух или использовать только некоторые параметры правила typedef .

В долгосрочной перспективе, я думаю, мы либо захотим интегрировать no-inferrable-types в правило typedef , либо по крайней мере захотим, чтобы TSLint обнаруживал конфликтующие конфигурации, такие как включение обоих правил.

Я столкнулся с той же проблемой.
На данный момент я отключил не выводимые типы.

Да, то же самое здесь, я хотел бы иметь возможность сосуществования обоих правил.
Я бы не хотел, чтобы правило typedef срабатывало, если можно вывести тип переменной.
т.е. "типы без выводов" должны иметь приоритет над "typedef"

+1

let id: number = 0;
for (let job: string of NAMES_PROFFESSIONS) {
     /** some code */
     id++;
}

(no-inferrable-types) Тип LHS (число), выведенный выражением RHS, удалить аннотацию типа

+1

Включает ли ваше определение «выводимых» типов назначения конструктора?

// BAD (this hurts my eyes to read)
let labels: Map<string, string> = new Map<string, string>();
// GOOD (type is obvious)
let labels = new Map<string, string>();

но также...

// BAD (in a diff, it's not obvious what this type is)
let labels = this.buildLabels();
// GOOD
let labels: Map<string, string> = this.buildLabels();

Да, это опасно. Если я хочу упростить свой код и запретить использовать объявление типа для напрямую инициализируемых переменных, я не могу сделать это строго, и это приводит к такой вещи:

let x = 2;
let y;
let z: number;

x = 1;
y = 1;
z = 1;
x = 's'; // Type 'string' is not assignable to type 'number'
y = 's'; // It's OK
z = 's'; // Type 'string' is not assignable to type 'number'

Это может быть очень полезной опцией, позволяющей пропускать объявление типа только для инициализированных переменных.

… и действительно не только для примитивных типов, как говорит @pgonzal !
Посмотрите на это, это ужасно:

const onChange: () => void = () => this.update();

:+1: В идеале (imo) я хотел бы сказать «всегда требуется typedef, если только тип не выводится». Что я не думаю, что сейчас возможно.

Я столкнулся с этим и сделал флаг ignore-params , который помогает в моем случае. Я хочу принудительно указать typedef для всех параметров метода/функции, даже если их можно легко вывести.

См. PR: #1190, если хотите попробовать.

Прошло некоторое время с тех пор, как был представлен оригинальный вопрос. Является ли рекомендуемым вариантом на данный момент отключить no-inferrable-types и включить тип на все? Любые другие попытки включить и объединить no-inferrable-types и typedef выглядят как взлом и приводят к куче бессмысленных предупреждений. Надеюсь на лучшее решение в ближайшем будущем.

@corydeppen Обратите внимание на 8 одобрений предложения @englercj выше. Неясно, что означает «комбинировать» в вашем комментарии «похоже на взлом». Если вы имеете в виду «использовать вместе в tslint.json , то да. Но «объединение» аргумента optional-inferrable-types в typedef было бы здорово (по крайней мере, для 9 из нас).

Можем ли мы получить обновленную информацию об этом, пожалуйста?

Я думаю, что лучший способ справиться с этим — объявить устаревшим no-inferrable-types и просто передать объект опции в typedef , чтобы игнорировать отсутствие определений типа, если тип выводится в соответствии с определенными шаблонами, как initialized , initialized primitives , call signatures и другие шаблоны, которые удовлетворят наши потребности как разработчиков.

Для меня это имеет больше смысла, потому что всегда должен быть typedef, если только что-то не говорит вам, что это за тип функции. И это также можно было бы настроить, потому что, возможно, мы хотим, чтобы инициализированный properties в классе имел выводимый тип, но не для call signatures , например.

Было бы здорово, если бы кто-то мог принять участие, чтобы исправить это. До тех пор мы вынуждены выбирать между «недостаточно объявлений типов для чтения» и «загромождены слишком большим количеством объявлений типов».

Эта проблема была открыта с 3 октября 2015 года — с тех пор моя команда создала около 2000 исходных файлов TypeScript, которые загромождены слишком большим количеством объявлений типов.

typedef принимает конфигурацию. Так что, возможно, это просто еще одна конфигурация, чтобы игнорировать определение типа, если тип выводим, что означает

Просто введите везде, где не инициализируется.

Похоже, что из-за отсутствия четкого консенсуса в отношении того, как решать этот вопрос, не наблюдается никакого прогресса. Пример комментария: https://github.com/theia-ide/theia/issues/356#issuecomment -319350833

Я подозреваю, что мы все согласны с тем, что любое решение лучше, чем оставить все как есть. Если вы считаете, что любое изменение статус-кво в отношении этого вопроса хорошо, пожалуйста, 👍 этот комментарий. Если вы достаточно осведомлены, чтобы создать PR для решения этой проблемы, пожалуйста, помогите всем нам ❤️ .

Приму PR на:

  • добавить параметр к typedef , который позволяет игнорировать случаи, когда no-inferrable-types говорит не предоставлять тип

Typedef принимает конфигурацию. Так что, возможно, это просто еще одна конфигурация, чтобы просто игнорировать определение типа, если тип выводится, что означает «Просто введите везде, где не инициализируется».

Правило typedef предназначено для людей, которым нравится иметь явные определения типов в своей кодовой базе. Если вы хотите, чтобы приведенное выше поведение «просто печатало везде, где не инициализируется», вам лучше отключить typedef и убедиться, что у вас включена noImplictAny в качестве параметра компилятора TypeScript.

Есть также сложный случай, когда некоторые вещи, которые инициализируются, все равно нуждаются в typedef, как в следующем фрагменте кода:

interface Literal {
    field: "value"
}

const literal0 = {
    field: "value",
};
const literal1: Literal = {
    field: "value",
};

const func = (obj: Literal) => { };
func(literal0);  // Error! Type 'string' is not assignable to type '"value"'.
func(literal1);

Кроме того, пока мы исправим это, хотелось бы отметить, что, вероятно, есть некоторые отличные сторонние правила, такие как no-unnecessary-type-annotation (https://github.com/ajafff/tslint-consistent-codestyle/blob/ master/docs/no-ненужный-type-annotation.md), например. Если кто-то знает о каких-либо других сторонних правилах, обеспечивающих желаемое поведение, опубликуйте их здесь, и мы сможем официально их порекомендовать или внедрить в ядро, если это имеет смысл.

@JKillian спасибо за рекомендацию, я думаю, это именно то, что я хотел. Есть очень хороший пост о том, как избегать типа any : не используйте «голый любой», вместо этого создайте «любой интерфейс».

О:

interface Literal {
    field: "value"
}

const literal0 = {
    field: "value",
};
const literal1: Literal = {
    field: "value",
};

const func = (obj: Literal) => { };
func(literal0);  // Error! Type 'string' is not assignable to type '"value"'.
func(literal1);

Я не понимаю, как это может быть нежелательным поведением или сложным случаем. Вы хотите убедиться, что obj имеет свойство field со значением value , и даже когда вы инициализируете literal0 со свойством, которое похоже на ограничения , вы можете изменить это на другую строку.

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

У меня следующая конфигурация:
json "no-inferrable-types": true, "typedef": [true, "call-signature", "parameter"],
И этот код:
javascript private static readonly DEVICE_UID: string = 'device_uid'; private static readonly DEVICE_PLATFORM: string = 'browser'; private static readonly AGENT_DEFAULT_ICON = 'http://localhost:3000/icon.png';

Почему я не получаю ошибку в двух первых объявлениях?

@sandrocsimas Интересно, но я думаю, что не по теме; AFAICT, что проблема не связана с этой проблемой. Я предлагаю вам начать другой выпуск (fwiw!).

@estaub , да, я буду. Я получаю такое же поведение даже без правила typedef.

@sandrocsimas это потому, что это свойство доступно только для чтения, и такой Typescript выводит его тип как литерал. Вводя его как строку, вы говорите, что она должна иметь строку, она не обязательно будет иметь это буквальное значение, и значение не должно изменяться статически.

Было бы неплохо иметь правило «require-typedef-except-inferrable».

@FiretronP75 , как сказал @JKillian , это всего лишь noImplicitAny вариант TSC.

@michaeljota спасибо, я не знал, что опция компилятора noImplicitAny дает исключения для выводов. Тем не менее, было бы неплохо иметь в tslint возможность сделать предупреждение вместо прерывания компиляции и иметь флаги комментариев tslint.

Я понимаю, почему это было бы желательно, но имея в качестве примера no-unused-variables , я не думаю, что варианты использования, охватываемые TSC, будут поддерживаться командой TSLint. Я знаю, что это не то же самое, что _ошибка линтера_, чем _ошибка компилятора_, но, в конце концов, обе они направлены на то, чтобы написать лучший код. В наши дни с такими решениями, как Webpack или Parcel, которые позволяют компилировать и запускать код даже с ошибками TSC, я не вижу в этом реальной проблемы.

Это было исправлено в последней версии?

Я до сих пор не думаю, что это есть в дорожной карте. Вам следует рассмотреть возможность использования noImplicitAny от TSC

☠️ Пришло время TSLint! ☠️

TSLint больше не принимает большинство запросов функций согласно #4534. См. typescript-eslint.io , чтобы узнать о новом блестящем способе линтинга вашего кода TypeScript с помощью ESLint . ✨

Было приятно открывать исходный код со всеми вами!

🤖 Бип-буп! 👉 TSLint устарел 👈 _(#4534)_ и вам следует переключиться на typescript-eslint ! 🤖

🔒 Эта проблема заблокирована, чтобы избежать дальнейших ненужных обсуждений. Спасибо! 👋

Была ли эта страница полезной?
0 / 5 - 0 рейтинги