Update dependencies and lint for no-unsafe-any#2544
Conversation
1e9977f to
d9faf67
Compare
src/language/formatter/formatter.ts
Outdated
|
|
||
| export type ConsumerType = "human" | "machine"; | ||
|
|
||
| export interface FormatterStatic { |
There was a problem hiding this comment.
rename to FormatterConstructor?
|
|
||
| const moduleDirectory = path.dirname(module.filename); | ||
| const CORE_RULES_DIRECTORY = path.resolve(moduleDirectory, ".", "rules"); | ||
| const cachedRules = new Map<string, typeof AbstractRule | null>(); // null indicates that the rule was not found |
There was a problem hiding this comment.
actually I found this to be clearer
There was a problem hiding this comment.
But rules aren't actually guaranteed to be implemented by AbstractRule subclasses, are they?
There was a problem hiding this comment.
Now that it's renamed to RuleConstructor I'm fine with it.
src/language/rule/rule.ts
Outdated
| import {arrayify, flatMap} from "../../utils"; | ||
| import {IWalker} from "../walker"; | ||
|
|
||
| export interface RuleStatic { |
There was a problem hiding this comment.
also rename to RuleConstructor?
src/ruleLoader.ts
Outdated
|
|
||
| let Rule: typeof AbstractRule | null = null; | ||
| let Rule: RuleStatic | null = null; | ||
| if (absolutePath != null) { |
There was a problem hiding this comment.
this comparison can be strict
| @@ -87,7 +87,7 @@ class NoInferredEmptyObjectTypeRule extends Lint.ProgramAwareRuleWalker { | |||
| let isAnonymous: boolean; | |||
| if (ts.ObjectFlags == null) { | |||
| // typescript 2.0.x specific code | |||
There was a problem hiding this comment.
this branch can be removed since support for ts 2.0.x was dropped in v5.0.0
| */ | ||
| export function camelize(stringWithHyphens: string): string { | ||
| return stringWithHyphens.replace(/-(.)/g, (_, nextLetter) => nextLetter.toUpperCase()); | ||
| return stringWithHyphens.replace(/-(.)/g, (_, nextLetter) => (nextLetter as string).toUpperCase()); |
There was a problem hiding this comment.
consider adding the type annotation to the parameter instead of asserting it
There was a problem hiding this comment.
I don't like that style since it behaves the same as a typecast but doesn't look like one. Was actually considering writing a lint rule for that.
There was a problem hiding this comment.
um, I don't think that's quite right @andy-hanson. type assertions (as string) are generally less safe than typedefs, because the assignability checks for the latter are stricter
There was a problem hiding this comment.
A type annotation in a callback is unsafe.
declare function f(cb: (x: {}) => void): void;
f((n: number) => { console.log(n + 1); }); // Huh, no error?A type assertion is of course also unsafe, but it's more obvious that it is.
src/ruleLoader.ts
Outdated
| } | ||
| } | ||
| return undefined; | ||
| return null; |
There was a problem hiding this comment.
why the switch to nulls? can't we use undefined?
There was a problem hiding this comment.
We use cachedRules.set(fullPath, Rule);, so if Rule is undefined, it will look like we didn't cache a result at all. I actually already had to do this in #2369.
There was a problem hiding this comment.
maybe we should use a string literal like "not-found" or "load-error" instead of null
| */ | ||
| export function camelize(stringWithHyphens: string): string { | ||
| return stringWithHyphens.replace(/-(.)/g, (_, nextLetter) => nextLetter.toUpperCase()); | ||
| return stringWithHyphens.replace(/-(.)/g, (_, nextLetter) => (nextLetter as string).toUpperCase()); |
There was a problem hiding this comment.
um, I don't think that's quite right @andy-hanson. type assertions (as string) are generally less safe than typedefs, because the assignability checks for the latter are stricter
| } catch (error) { | ||
| if (error.name === FatalError.NAME) { | ||
| console.error(error.message); | ||
| if ((error as FatalError).name === FatalError.NAME) { |
There was a problem hiding this comment.
can you use error: FatalError on the line above instead?
There was a problem hiding this comment.
No, TS doesn't allow a type annotation there. It wouldn't be safe anyway since TS doesn't have checked exceptions.
src/rules/noUnsafeAnyRule.ts
Outdated
| /* tslint:enable:object-literal-sort-keys */ | ||
|
|
||
| public static FAILURE_STRING = "Unsafe use of expression of type 'any'."; | ||
| public static FAILURE_STRING: string = "Unsafe use of expression of type 'any'."; |
There was a problem hiding this comment.
surely this isn't necessary?
There was a problem hiding this comment.
Whoops, no idea why that got there!
|
|
||
| public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { | ||
| const limit: number = this.ruleArguments[0] || Rule.DEFAULT_ALLOWED_BLANKS; | ||
| const limit = this.ruleArguments[0] as number | undefined || Rule.DEFAULT_ALLOWED_BLANKS; |
There was a problem hiding this comment.
why the switch from typedef to type assertion?
There was a problem hiding this comment.
A typedef const x: number = thisIsAny; is flagged by the no-unsafe-any rule, since it looks safe but isn't. const x = thisIsAny as number; is OK since that's obviously an assertion.
src/configuration.ts
Outdated
| function getHomeDir() { | ||
| function getHomeDir(): string | undefined { | ||
| const environment = global.process.env; | ||
| const paths = [ |
There was a problem hiding this comment.
prefer type annotation on paths instead of the function return value. or both
src/ruleLoader.ts
Outdated
| const ruleSpecificList = enableDisableRules || []; | ||
| ruleOptions.disabledIntervals = buildDisabledIntervalsFromSwitches(ruleSpecificList); | ||
| rules.push(new (Rule as any)(ruleOptions)); | ||
| rules.push(new (Rule as any)(ruleOptions) as IRule); |
src/configuration.ts
Outdated
| * limitations under the License. | ||
| */ | ||
|
|
||
| // tslint:disable no-unsafe-any (TODO) |
src/formatterLoader.ts
Outdated
| if (fs.existsSync(`${fullPath}.js`)) { | ||
| const formatterModule = require(fullPath); | ||
| return formatterModule.Formatter; | ||
| return formatterModule.Formatter; // tslint:disable-line no-unsafe-any |
There was a problem hiding this comment.
instead of disabling rule, cast the require to an interface like { Formatter: FormatterConstructor }
src/formatterLoader.ts
Outdated
| return undefined; | ||
| } | ||
| return require(src).Formatter; | ||
| return require(src).Formatter; // tslint:disable-line no-unsafe-any |
src/ruleLoader.ts
Outdated
| } | ||
| } | ||
| return undefined; | ||
| return null; |
There was a problem hiding this comment.
maybe we should use a string literal like "not-found" or "load-error" instead of null
src/ruleLoader.ts
Outdated
| Rule = loadRule(absolutePath, ruleName); | ||
| let Rule: RuleConstructor | null = null; | ||
| if (absolutePath !== undefined) { | ||
| Rule = loadRule(absolutePath, ruleName); // tslint:disable-line no-unsafe-any |
There was a problem hiding this comment.
I don't think you need to disable the rule here
| } | ||
|
|
||
| // tslint:disable-next-line no-unsafe-any | ||
| return { order: categoryFromOption(firstOption[OPTION_ORDER]), alphabetize: !!firstOption[OPTION_ALPHABETIZE] }; |
There was a problem hiding this comment.
instead of disabling, annotate firstOption as type Options, then call using firstOption.order and firstOption.alphabetize
src/tslint-cli.ts
Outdated
| * limitations under the License. | ||
| */ | ||
|
|
||
| // tslint:disable no-unsafe-any (TODO) |
There was a problem hiding this comment.
I don't think you need to disable the rule here
src/configuration.ts
Outdated
| } | ||
|
|
||
| /** | ||
| /**findRule |
src/ruleLoader.ts
Outdated
| const moduleDirectory = path.dirname(module.filename); | ||
| const CORE_RULES_DIRECTORY = path.resolve(moduleDirectory, ".", "rules"); | ||
| const cachedRules = new Map<string, typeof AbstractRule | null>(); // null indicates that the rule was not found | ||
| const cachedRules = new Map<string, RuleConstructor | "not-found">(); // null indicates that the rule was not found |
There was a problem hiding this comment.
can remove/update this comment
PR checklist
Overview of change:
The
no-unsafe-anyrule mostly just required appropriate casts, but in the case ofFormatterFunctionit seems to have discovered a bug -- formatters actually seem to have to be new-able. So created aFormatterStaticinstead. This is technically a breaking change, but code that compiled againstFormatterFunctionwould have been wrong.