forked from microsoft/TypeScript
-
Notifications
You must be signed in to change notification settings - Fork 0
Strict assignment #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
31e7372
initial commit of --strictAssignment option
kevinbarabash dfe357b
add remaining test cases to test-calls.ts, cleanup propertyRelatedTo
kevinbarabash a6c1b81
support generics
kevinbarabash 32ea288
add messages for errors specific to --strictAssignment
kevinbarabash cc0a405
update existing test-*.ts files to real unit tests, fix lint
kevinbarabash c286684
add tests for overloading functions
kevinbarabash 4b2ef23
add support for jsx attributes
kevinbarabash 49dbcfe
add a pragma to conditionally enable strict-assignment check for code…
kevinbarabash File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// @strict-assignment | ||
|
||
declare class Animal {} | ||
declare class Cat { purr(): void } | ||
declare class Dog { bark(): void } | ||
|
||
declare function foo(animals: Animal[]): void; | ||
|
||
type CatNode = { animal: Cat }; | ||
type AnimalNode = { animal: Animal }; | ||
type ReadonlyAnimalNode = { animal: Readonly<Animal> }; | ||
|
||
type CatsNode = { animals: Cat[] }; | ||
type AnimalsNode = { animals: Animal[] }; | ||
type ReadonlyAnimalsNode = { animals: ReadonlyArray<Animal> }; |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/// <reference path="./libdef.d.ts" /> | ||
|
||
module TestAssignment { | ||
type Node = { id: number | string }; | ||
type NumNode = { id: number}; | ||
|
||
const numNode: NumNode = { id: 5 }; | ||
const node1: Node = numNode; // error, prevent setting id to a string | ||
node1.id = "five"; | ||
|
||
const node2: Node = { id: 5 }; // okay, since the source is an object literal | ||
node2.id = "five"; | ||
|
||
const readonlyNode: Readonly<Node> = numNode; | ||
readonlyNode.id = "five"; // error, readonlyNode is readonly | ||
|
||
const cats: Cat[] = [new Cat]; | ||
|
||
foo(cats); // error, prevent a Dog from getting added to cats | ||
foo([new Cat]); // okay | ||
|
||
const catNode: CatNode = { animal: new Cat }; | ||
const cat = new Cat; | ||
|
||
const animalNode1: AnimalNode = catNode; // error | ||
const animalNode2: AnimalNode = { animal: new Cat }; // okay | ||
const animalNode3: AnimalNode = { animal: cat }; // okay | ||
const animalNode4: Readonly<AnimalNode> = catNode; // okay | ||
} |
5 changes: 5 additions & 0 deletions
5
...ines/reference/showConfig/Shows tsconfig for single option/strictAssignment/tsconfig.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"compilerOptions": { | ||
"strictAssignment": true | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
tests/cases/compiler/strictAssignment1.ts(10,11): error TS2755: Type 'Cat[]' is not assignable to type 'Animal[]'. Covariant assignment of aliases to non-readonly targets are unsafe. | ||
tests/cases/compiler/strictAssignment1.ts(24,11): error TS2755: Type 'CatNode' is not assignable to type 'AnimalNode'. Covariant assignment of aliases to non-readonly targets are unsafe. | ||
tests/cases/compiler/strictAssignment1.ts(40,11): error TS2755: Type 'CatsNode' is not assignable to type 'AnimalsNode'. Covariant assignment of aliases to non-readonly targets are unsafe. | ||
tests/cases/compiler/strictAssignment1.ts(47,11): error TS2322: Type '{ animals: Cat[]; }' is not assignable to type 'AnimalsNode'. | ||
Types of property 'animals' are incompatible. | ||
Type 'Cat[]' is not assignable to type 'Animal[]'. Covariant assignment of aliases to non-readonly targets are unsafe. | ||
tests/cases/compiler/strictAssignment1.ts(55,11): error TS2755: Type 'CatsNode' is not assignable to type 'ReadonlyAnimalsNode'. Covariant assignment of aliases to non-readonly targets are unsafe. | ||
tests/cases/compiler/strictAssignment1.ts(64,11): error TS2322: Type 'CatsNode' is not assignable to type 'Readonly<AnimalsNode>'. | ||
Types of property 'animals' are incompatible. | ||
Type 'Cat[]' is not assignable to type 'Animal[]'. Covariant assignment of aliases to non-readonly targets are unsafe. | ||
tests/cases/compiler/strictAssignment1.ts(69,11): error TS2322: Type '{ animals: Cat[]; }' is not assignable to type 'Readonly<AnimalsNode>'. | ||
Types of property 'animals' are incompatible. | ||
Type 'Cat[]' is not assignable to type 'Animal[]'. Covariant assignment of aliases to non-readonly targets are unsafe. | ||
|
||
|
||
==== tests/cases/compiler/strictAssignment1.ts (7 errors) ==== | ||
module StrictAssignment1 { | ||
class Animal {} | ||
class Cat { purr() {} } | ||
class Dog { bark() {} } | ||
|
||
// Arrays | ||
const cats: Cat[] = [new Cat]; | ||
|
||
// TODO: write tests that show the order of the next two statements don't matter | ||
const animals1: Animal[] = cats; // error: alias assignments are invariant | ||
~~~~~~~~ | ||
!!! error TS2755: Type 'Cat[]' is not assignable to type 'Animal[]'. Covariant assignment of aliases to non-readonly targets are unsafe. | ||
!!! related TS2728 tests/cases/compiler/strictAssignment1.ts:3:17: 'purr' is declared here. | ||
const animals2: Animal[] = [new Cat]; // okay: covariant is safe since source is a literal | ||
const animals3: ReadonlyArray<Animal> = cats; // okay: covariant is safe since target is readonly | ||
|
||
// TODO: check assignments as well as variable declarations | ||
|
||
// // Simple Objects | ||
type CatNode = { animal: Cat }; | ||
type AnimalNode = { animal: Animal }; | ||
type ReadonlyAnimalNode = { animal: Readonly<Animal> }; | ||
|
||
const catNode: CatNode = { animal: new Cat }; | ||
const cat = new Cat; | ||
|
||
const animalNode1: AnimalNode = catNode; // error | ||
~~~~~~~~~~~ | ||
!!! error TS2755: Type 'CatNode' is not assignable to type 'AnimalNode'. Covariant assignment of aliases to non-readonly targets are unsafe. | ||
const animalNode2: AnimalNode = { animal: new Cat }; // okay | ||
const animalNode3: AnimalNode = { animal: cat }; // okay | ||
const animalNode4: Readonly<AnimalNode> = catNode; // okay | ||
|
||
// Need to check if the target is readonly | ||
const animalNode5: ReadonlyAnimalNode = { animal: cat }; // okay | ||
|
||
// Nested objects | ||
type CatsNode = { animals: Cat[] }; | ||
type AnimalsNode = { animals: Animal[] }; | ||
type ReadonlyAnimalsNode = { animals: ReadonlyArray<Animal> }; | ||
|
||
const catsNode: CatsNode = { animals: [new Cat] }; | ||
// const cats: Cat[] = [new Cat]; | ||
|
||
const animalsNode1: AnimalsNode = catsNode; // error | ||
~~~~~~~~~~~~ | ||
!!! error TS2755: Type 'CatsNode' is not assignable to type 'AnimalsNode'. Covariant assignment of aliases to non-readonly targets are unsafe. | ||
// prevents animalsNode.animals = [new Dog] which would conflict | ||
// with CatsNode's definition of its animals property | ||
|
||
const animalsNode2: AnimalsNode = { animals: [new Cat] }; // okay | ||
// okay since we're not storing [new Cat] in a variable typed as a Cat[] | ||
|
||
const animalsNode3: AnimalsNode = { animals: cats }; // error | ||
~~~~~~~~~~~~ | ||
!!! error TS2322: Type '{ animals: Cat[]; }' is not assignable to type 'AnimalsNode'. | ||
!!! error TS2322: Types of property 'animals' are incompatible. | ||
!!! error TS2322: Type 'Cat[]' is not assignable to type 'Animal[]'. Covariant assignment of aliases to non-readonly targets are unsafe. | ||
// prevents animalsNode.animals.push(new Dog) which would add | ||
// a Dog to cats array | ||
|
||
const animalsNode4: ReadonlyAnimalsNode = { animals: cats }; // okay | ||
// okay since the animals property is a readonly array and we are unable | ||
// to add new elements to it. | ||
|
||
const animalsNode5: ReadonlyAnimalsNode = catsNode; // error | ||
~~~~~~~~~~~~ | ||
!!! error TS2755: Type 'CatsNode' is not assignable to type 'ReadonlyAnimalsNode'. Covariant assignment of aliases to non-readonly targets are unsafe. | ||
// prevents animalsNode.animals = [new Dog] which would conflict | ||
// with CatsNode's definition of its animals property | ||
|
||
const animalsNode6: Readonly<ReadonlyAnimalsNode> = catsNode; // okay | ||
// prevents both setting animals property to different from Cats[] and | ||
// prevents adding a Dog to the animals array which is typed as a Cats[] | ||
// on the right side | ||
|
||
const animalsNode7: Readonly<AnimalsNode> = catsNode; // error | ||
~~~~~~~~~~~~ | ||
!!! error TS2322: Type 'CatsNode' is not assignable to type 'Readonly<AnimalsNode>'. | ||
!!! error TS2322: Types of property 'animals' are incompatible. | ||
!!! error TS2322: Type 'Cat[]' is not assignable to type 'Animal[]'. Covariant assignment of aliases to non-readonly targets are unsafe. | ||
// while making AnimalsNode readonly prevents the reassignment of animals | ||
// to something other than Cat[], it's still possible to push a Dog to catsNode's | ||
// animals array. | ||
|
||
const animalsNode8: Readonly<AnimalsNode> = { animals: cats }; // error | ||
~~~~~~~~~~~~ | ||
!!! error TS2322: Type '{ animals: Cat[]; }' is not assignable to type 'Readonly<AnimalsNode>'. | ||
!!! error TS2322: Types of property 'animals' are incompatible. | ||
!!! error TS2322: Type 'Cat[]' is not assignable to type 'Animal[]'. Covariant assignment of aliases to non-readonly targets are unsafe. | ||
|
||
const animalsNode9: Readonly<ReadonlyAnimalsNode> = { animals: cats }; | ||
} | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
//// [strictAssignment1.ts] | ||
module StrictAssignment1 { | ||
class Animal {} | ||
class Cat { purr() {} } | ||
class Dog { bark() {} } | ||
|
||
// Arrays | ||
const cats: Cat[] = [new Cat]; | ||
|
||
// TODO: write tests that show the order of the next two statements don't matter | ||
const animals1: Animal[] = cats; // error: alias assignments are invariant | ||
const animals2: Animal[] = [new Cat]; // okay: covariant is safe since source is a literal | ||
const animals3: ReadonlyArray<Animal> = cats; // okay: covariant is safe since target is readonly | ||
|
||
// TODO: check assignments as well as variable declarations | ||
|
||
// // Simple Objects | ||
type CatNode = { animal: Cat }; | ||
type AnimalNode = { animal: Animal }; | ||
type ReadonlyAnimalNode = { animal: Readonly<Animal> }; | ||
|
||
const catNode: CatNode = { animal: new Cat }; | ||
const cat = new Cat; | ||
|
||
const animalNode1: AnimalNode = catNode; // error | ||
const animalNode2: AnimalNode = { animal: new Cat }; // okay | ||
const animalNode3: AnimalNode = { animal: cat }; // okay | ||
const animalNode4: Readonly<AnimalNode> = catNode; // okay | ||
|
||
// Need to check if the target is readonly | ||
const animalNode5: ReadonlyAnimalNode = { animal: cat }; // okay | ||
|
||
// Nested objects | ||
type CatsNode = { animals: Cat[] }; | ||
type AnimalsNode = { animals: Animal[] }; | ||
type ReadonlyAnimalsNode = { animals: ReadonlyArray<Animal> }; | ||
|
||
const catsNode: CatsNode = { animals: [new Cat] }; | ||
// const cats: Cat[] = [new Cat]; | ||
|
||
const animalsNode1: AnimalsNode = catsNode; // error | ||
// prevents animalsNode.animals = [new Dog] which would conflict | ||
// with CatsNode's definition of its animals property | ||
|
||
const animalsNode2: AnimalsNode = { animals: [new Cat] }; // okay | ||
// okay since we're not storing [new Cat] in a variable typed as a Cat[] | ||
|
||
const animalsNode3: AnimalsNode = { animals: cats }; // error | ||
// prevents animalsNode.animals.push(new Dog) which would add | ||
// a Dog to cats array | ||
|
||
const animalsNode4: ReadonlyAnimalsNode = { animals: cats }; // okay | ||
// okay since the animals property is a readonly array and we are unable | ||
// to add new elements to it. | ||
|
||
const animalsNode5: ReadonlyAnimalsNode = catsNode; // error | ||
// prevents animalsNode.animals = [new Dog] which would conflict | ||
// with CatsNode's definition of its animals property | ||
|
||
const animalsNode6: Readonly<ReadonlyAnimalsNode> = catsNode; // okay | ||
// prevents both setting animals property to different from Cats[] and | ||
// prevents adding a Dog to the animals array which is typed as a Cats[] | ||
// on the right side | ||
|
||
const animalsNode7: Readonly<AnimalsNode> = catsNode; // error | ||
// while making AnimalsNode readonly prevents the reassignment of animals | ||
// to something other than Cat[], it's still possible to push a Dog to catsNode's | ||
// animals array. | ||
|
||
const animalsNode8: Readonly<AnimalsNode> = { animals: cats }; // error | ||
|
||
const animalsNode9: Readonly<ReadonlyAnimalsNode> = { animals: cats }; | ||
} | ||
|
||
|
||
//// [strictAssignment1.js] | ||
var StrictAssignment1; | ||
(function (StrictAssignment1) { | ||
var Animal = /** @class */ (function () { | ||
function Animal() { | ||
} | ||
return Animal; | ||
}()); | ||
var Cat = /** @class */ (function () { | ||
function Cat() { | ||
} | ||
Cat.prototype.purr = function () { }; | ||
return Cat; | ||
}()); | ||
var Dog = /** @class */ (function () { | ||
function Dog() { | ||
} | ||
Dog.prototype.bark = function () { }; | ||
return Dog; | ||
}()); | ||
// Arrays | ||
var cats = [new Cat]; | ||
// TODO: write tests that show the order of the next two statements don't matter | ||
var animals1 = cats; // error: alias assignments are invariant | ||
var animals2 = [new Cat]; // okay: covariant is safe since source is a literal | ||
var animals3 = cats; // okay: covariant is safe since target is readonly | ||
var catNode = { animal: new Cat }; | ||
var cat = new Cat; | ||
var animalNode1 = catNode; // error | ||
var animalNode2 = { animal: new Cat }; // okay | ||
var animalNode3 = { animal: cat }; // okay | ||
var animalNode4 = catNode; // okay | ||
// Need to check if the target is readonly | ||
var animalNode5 = { animal: cat }; // okay | ||
var catsNode = { animals: [new Cat] }; | ||
// const cats: Cat[] = [new Cat]; | ||
var animalsNode1 = catsNode; // error | ||
// prevents animalsNode.animals = [new Dog] which would conflict | ||
// with CatsNode's definition of its animals property | ||
var animalsNode2 = { animals: [new Cat] }; // okay | ||
// okay since we're not storing [new Cat] in a variable typed as a Cat[] | ||
var animalsNode3 = { animals: cats }; // error | ||
// prevents animalsNode.animals.push(new Dog) which would add | ||
// a Dog to cats array | ||
var animalsNode4 = { animals: cats }; // okay | ||
// okay since the animals property is a readonly array and we are unable | ||
// to add new elements to it. | ||
var animalsNode5 = catsNode; // error | ||
// prevents animalsNode.animals = [new Dog] which would conflict | ||
// with CatsNode's definition of its animals property | ||
var animalsNode6 = catsNode; // okay | ||
// prevents both setting animals property to different from Cats[] and | ||
// prevents adding a Dog to the animals array which is typed as a Cats[] | ||
// on the right side | ||
var animalsNode7 = catsNode; // error | ||
// while making AnimalsNode readonly prevents the reassignment of animals | ||
// to something other than Cat[], it's still possible to push a Dog to catsNode's | ||
// animals array. | ||
var animalsNode8 = { animals: cats }; // error | ||
var animalsNode9 = { animals: cats }; | ||
})(StrictAssignment1 || (StrictAssignment1 = {})); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing this line results in code in test.ts using these declarations with strict-assignment checking even if when using the
--strict-assignment
flag.