Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions docs/rules/no_legacy_type_assertion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Disallows the use of legacy `<Type> value` type assertion syntax in TypeScript
code.

`<Type> value` casting syntax is considered to be outdated because it does not
work in JSX. Instead, you should use `value as Type`.

### Invalid:

```typescript
const foo = <Foo> bar;
```

### Valid:

```typescript
const foo = bar as Foo;
```
2 changes: 2 additions & 0 deletions src/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ pub mod no_inner_declarations;
pub mod no_invalid_regexp;
pub mod no_invalid_triple_slash_reference;
pub mod no_irregular_whitespace;
pub mod no_legacy_type_assertion;
pub mod no_misused_new;
pub mod no_namespace;
pub mod no_new_symbol;
Expand Down Expand Up @@ -299,6 +300,7 @@ fn get_all_rules_raw() -> Vec<Box<dyn LintRule>> {
Box::new(no_invalid_regexp::NoInvalidRegexp),
Box::new(no_invalid_triple_slash_reference::NoInvalidTripleSlashReference),
Box::new(no_irregular_whitespace::NoIrregularWhitespace),
Box::new(no_legacy_type_assertion::NoLegacyTypeAssertion),
Box::new(no_misused_new::NoMisusedNew),
Box::new(no_namespace::NoNamespace),
Box::new(no_new_symbol::NoNewSymbol),
Expand Down
118 changes: 118 additions & 0 deletions src/rules/no_legacy_type_assertion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

use std::borrow::Cow;

use super::{Context, LintRule};
use crate::diagnostic::{LintFix, LintFixChange};
use crate::handler::{Handler, Traverse};
use crate::Program;
use deno_ast::{view as ast_view, MediaType, SourceRanged};

#[derive(Debug)]
pub struct NoLegacyTypeAssertion;

const CODE: &str = "no-legacy-type-assertion";
const MESSAGE: &str =
"TypeScript's `<Type> value` type assertion syntax is discouraged to use";
const HINT: &str = "Use `as` assertion syntax instead";
const FIX_DESC: &str = "Convert to `as` assertion";

impl LintRule for NoLegacyTypeAssertion {
fn tags(&self) -> &'static [&'static str] {
&["recommended"]
}

fn code(&self) -> &'static str {
CODE
}

fn lint_program_with_ast_view(
&self,
context: &mut Context,
program: Program<'_>,
) {
// The syntax can't appear in js, or jsx/tsx, or d.ts files.
if matches!(
context.media_type(),
MediaType::TypeScript | MediaType::Mts | MediaType::Cts
) {
NoLegacyTypeAssertionHandler.traverse(program, context);
}
}

#[cfg(feature = "docs")]
fn docs(&self) -> &'static str {
include_str!("../../docs/rules/no_legacy_type_assertion.md")
}
}

struct NoLegacyTypeAssertionHandler;

impl Handler for NoLegacyTypeAssertionHandler {
fn ts_type_assertion(
&mut self,
n: &ast_view::TsTypeAssertion,
ctx: &mut Context,
) {
let expr = n.expr.text_fast(ctx.parsed_source());
let typ = n.type_ann.text_fast(ctx.parsed_source());
let fixed = format!("({} as {})", expr, typ);
ctx.add_diagnostic_with_fixes(
n.range(),
CODE,
MESSAGE,
Some(HINT.to_owned()),
vec![LintFix {
changes: vec![LintFixChange {
new_text: Cow::Owned(fixed),
range: n.range(),
}],
description: Cow::Borrowed(FIX_DESC),
}],
);
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn no_legacy_type_assertion_valid() {
assert_lint_ok! {
NoLegacyTypeAssertion,
filename: "file:///foo.ts",

r#"const a = 1 as number"#,
};
}

#[test]
fn no_legacy_type_assertion_invalid() {
assert_lint_err! {
NoLegacyTypeAssertion,
"<number> 1": [
{
col: 0,
message: MESSAGE,
hint: HINT,
fix: (
"Convert to `as` assertion",
"(1 as number)"
)
},
],
"const x = 5 + <number> 5;": [
{
col: 14,
message: MESSAGE,
hint: HINT,
fix: (
"Convert to `as` assertion",
"const x = 5 + (5 as number);"
)
}
],
};
}
}