From c9da70560fd43792263a5738d57d7ef4ddf9eb69 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 23 May 2017 14:35:05 -0700 Subject: [PATCH] Update tests 1. Accept baselines 2. Fix APISample_watcher 3. Switch checker to use JSDOc for isWeak Some of the baselines seem incorrect or weirder than before. --- src/compiler/checker.ts | 6 +- .../baselines/reference/APISample_watcher.js | 2 +- .../reference/controlFlowInstanceof.types | 2 +- .../reference/generatorTypeCheck63.errors.txt | 26 +- ...btypingWithObjectMembersOptionality3.types | 4 +- ...btypingWithObjectMembersOptionality4.types | 4 +- .../tsxAttributeResolution1.errors.txt | 18 +- .../tsxAttributeResolution11.errors.txt | 6 +- .../tsxElementResolution11.errors.txt | 6 +- .../reference/underscoreTest1.errors.txt | 907 ------------------ tests/baselines/reference/weakType.errors.txt | 41 + tests/baselines/reference/weakType.js | 29 + tests/baselines/reference/weakType.symbols | 27 - tests/baselines/reference/weakType.types | 30 - tests/cases/compiler/APISample_watcher.ts | 2 +- 15 files changed, 115 insertions(+), 995 deletions(-) delete mode 100644 tests/baselines/reference/underscoreTest1.errors.txt create mode 100644 tests/baselines/reference/weakType.errors.txt delete mode 100644 tests/baselines/reference/weakType.symbols delete mode 100644 tests/baselines/reference/weakType.types diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5885641cb3f..e637d786aae 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9392,8 +9392,10 @@ namespace ts { return result; } - // A type is 'weak' if it is an object type with at least one optional property - // and no required properties or index signatures + /** + * A type is 'weak' if it is an object type with at least one optional property + * and no required properties or index signatures + */ function isWeak(type: Type) { let props = getPropertiesOfType(type); return type.flags & TypeFlags.Object && diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index b813a44f53e..f4d03f8f62f 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -11,7 +11,7 @@ declare var fs: { existsSync(path: string): boolean; readdirSync(path: string): string[]; readFileSync(filename: string, encoding?: string): string; - writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; + writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; } | string): void; watchFile(filename: string, options: { persistent?: boolean; interval?: number; }, listener: (curr: { mtime: Date }, prev: { mtime: Date }) => void): void; }; declare var path: any; diff --git a/tests/baselines/reference/controlFlowInstanceof.types b/tests/baselines/reference/controlFlowInstanceof.types index 16d1ec71462..5b9ea793e7d 100644 --- a/tests/baselines/reference/controlFlowInstanceof.types +++ b/tests/baselines/reference/controlFlowInstanceof.types @@ -247,7 +247,7 @@ function goo(x: X) { x.y; >x.y : string ->x : Y +>x : X & Y >y : string } x; diff --git a/tests/baselines/reference/generatorTypeCheck63.errors.txt b/tests/baselines/reference/generatorTypeCheck63.errors.txt index ed2ed36a438..bef6a0bfff3 100644 --- a/tests/baselines/reference/generatorTypeCheck63.errors.txt +++ b/tests/baselines/reference/generatorTypeCheck63.errors.txt @@ -1,11 +1,12 @@ -tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(24,14): error TS2322: Type '(a: State | 1) => IterableIterator' is not assignable to type 'Strategy'. - Type 'IterableIterator' is not assignable to type 'IterableIterator'. - Type 'State | 1' is not assignable to type 'State'. - Type '1' is not assignable to type 'State'. +tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(24,61): error TS2345: Argument of type '(state: State) => IterableIterator' is not assignable to parameter of type '(a: StrategicState) => IterableIterator'. + Type 'IterableIterator' is not assignable to type 'IterableIterator'. + Type 'State | 1' is not assignable to type 'StrategicState'. + Type '1' is not assignable to type 'StrategicState'. tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(29,70): error TS7025: Generator implicitly has type 'IterableIterator' because it does not yield any values. Consider supplying a return type. tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(32,42): error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly. Type argument candidate 'State' is not a valid type argument because it is not a supertype of candidate '1'. -tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(36,14): error TS2322: Type '(a: State | 1) => IterableIterator' is not assignable to type 'Strategy'. +tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(36,62): error TS2345: Argument of type '(state: State) => IterableIterator' is not assignable to parameter of type '(a: StrategicState) => IterableIterator'. + Type 'IterableIterator' is not assignable to type 'IterableIterator'. ==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts (4 errors) ==== @@ -33,11 +34,11 @@ tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(36,14): err } export const Nothing: Strategy = strategy("Nothing", function* (state: State) { - ~~~~~~~ -!!! error TS2322: Type '(a: State | 1) => IterableIterator' is not assignable to type 'Strategy'. -!!! error TS2322: Type 'IterableIterator' is not assignable to type 'IterableIterator'. -!!! error TS2322: Type 'State | 1' is not assignable to type 'State'. -!!! error TS2322: Type '1' is not assignable to type 'State'. + ~~~~~~~~ +!!! error TS2345: Argument of type '(state: State) => IterableIterator' is not assignable to parameter of type '(a: StrategicState) => IterableIterator'. +!!! error TS2345: Type 'IterableIterator' is not assignable to type 'IterableIterator'. +!!! error TS2345: Type 'State | 1' is not assignable to type 'StrategicState'. +!!! error TS2345: Type '1' is not assignable to type 'StrategicState'. yield 1; return state; }); @@ -55,8 +56,9 @@ tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(36,14): err }); export const Nothing3: Strategy = strategy("Nothing", function* (state: State) { - ~~~~~~~~ -!!! error TS2322: Type '(a: State | 1) => IterableIterator' is not assignable to type 'Strategy'. + ~~~~~~~~ +!!! error TS2345: Argument of type '(state: State) => IterableIterator' is not assignable to parameter of type '(a: StrategicState) => IterableIterator'. +!!! error TS2345: Type 'IterableIterator' is not assignable to type 'IterableIterator'. yield state; return 1; }); \ No newline at end of file diff --git a/tests/baselines/reference/subtypingWithObjectMembersOptionality3.types b/tests/baselines/reference/subtypingWithObjectMembersOptionality3.types index 7f93418506f..9a61726dddc 100644 --- a/tests/baselines/reference/subtypingWithObjectMembersOptionality3.types +++ b/tests/baselines/reference/subtypingWithObjectMembersOptionality3.types @@ -69,8 +69,8 @@ var b: { Foo2: Derived; } >Derived : Derived var r = true ? a : b; // ok ->r : { Foo?: Base; } ->true ? a : b : { Foo?: Base; } +>r : { Foo?: Base; } | { Foo2: Derived; } +>true ? a : b : { Foo?: Base; } | { Foo2: Derived; } >true : true >a : { Foo?: Base; } >b : { Foo2: Derived; } diff --git a/tests/baselines/reference/subtypingWithObjectMembersOptionality4.types b/tests/baselines/reference/subtypingWithObjectMembersOptionality4.types index d1d00e8e1bc..056173dd97b 100644 --- a/tests/baselines/reference/subtypingWithObjectMembersOptionality4.types +++ b/tests/baselines/reference/subtypingWithObjectMembersOptionality4.types @@ -69,8 +69,8 @@ var b: { Foo2?: Derived; } >Derived : Derived var r = true ? a : b; // ok ->r : { Foo2?: Derived; } ->true ? a : b : { Foo2?: Derived; } +>r : { Foo: Base; } | { Foo2?: Derived; } +>true ? a : b : { Foo: Base; } | { Foo2?: Derived; } >true : true >a : { Foo: Base; } >b : { Foo2?: Derived; } diff --git a/tests/baselines/reference/tsxAttributeResolution1.errors.txt b/tests/baselines/reference/tsxAttributeResolution1.errors.txt index f6c84f80fa5..2fd16644f0b 100644 --- a/tests/baselines/reference/tsxAttributeResolution1.errors.txt +++ b/tests/baselines/reference/tsxAttributeResolution1.errors.txt @@ -1,12 +1,15 @@ tests/cases/conformance/jsx/file.tsx(23,8): error TS2322: Type '{ x: "0"; }' is not assignable to type 'Attribs1'. Types of property 'x' are incompatible. Type '"0"' is not assignable to type 'number'. -tests/cases/conformance/jsx/file.tsx(24,8): error TS2339: Property 'y' does not exist on type 'Attribs1'. -tests/cases/conformance/jsx/file.tsx(25,8): error TS2339: Property 'y' does not exist on type 'Attribs1'. +tests/cases/conformance/jsx/file.tsx(24,8): error TS2322: Type '{ y: 0; }' is not assignable to type 'Attribs1'. + Weak type 'Attribs1' has no properties in common with '{ y: 0; }'. +tests/cases/conformance/jsx/file.tsx(25,8): error TS2322: Type '{ y: "foo"; }' is not assignable to type 'Attribs1'. + Weak type 'Attribs1' has no properties in common with '{ y: "foo"; }'. tests/cases/conformance/jsx/file.tsx(26,8): error TS2322: Type '{ x: "32"; }' is not assignable to type 'Attribs1'. Types of property 'x' are incompatible. Type '"32"' is not assignable to type 'number'. -tests/cases/conformance/jsx/file.tsx(27,8): error TS2339: Property 'var' does not exist on type 'Attribs1'. +tests/cases/conformance/jsx/file.tsx(27,8): error TS2322: Type '{ var: "10"; }' is not assignable to type 'Attribs1'. + Weak type 'Attribs1' has no properties in common with '{ var: "10"; }'. tests/cases/conformance/jsx/file.tsx(29,1): error TS2322: Type '{}' is not assignable to type '{ reqd: string; }'. Property 'reqd' is missing in type '{}'. tests/cases/conformance/jsx/file.tsx(30,8): error TS2322: Type '{ reqd: 10; }' is not assignable to type '{ reqd: string; }'. @@ -44,10 +47,12 @@ tests/cases/conformance/jsx/file.tsx(30,8): error TS2322: Type '{ reqd: 10; }' i !!! error TS2322: Type '"0"' is not assignable to type 'number'. ; // Error, no property "y" ~~~~~ -!!! error TS2339: Property 'y' does not exist on type 'Attribs1'. +!!! error TS2322: Type '{ y: 0; }' is not assignable to type 'Attribs1'. +!!! error TS2322: Weak type 'Attribs1' has no properties in common with '{ y: 0; }'. ; // Error, no property "y" ~~~~~~~ -!!! error TS2339: Property 'y' does not exist on type 'Attribs1'. +!!! error TS2322: Type '{ y: "foo"; }' is not assignable to type 'Attribs1'. +!!! error TS2322: Weak type 'Attribs1' has no properties in common with '{ y: "foo"; }'. ; // Error, "32" is not number ~~~~~~ !!! error TS2322: Type '{ x: "32"; }' is not assignable to type 'Attribs1'. @@ -55,7 +60,8 @@ tests/cases/conformance/jsx/file.tsx(30,8): error TS2322: Type '{ reqd: 10; }' i !!! error TS2322: Type '"32"' is not assignable to type 'number'. ; // Error, no 'var' property ~~~~~~~~ -!!! error TS2339: Property 'var' does not exist on type 'Attribs1'. +!!! error TS2322: Type '{ var: "10"; }' is not assignable to type 'Attribs1'. +!!! error TS2322: Weak type 'Attribs1' has no properties in common with '{ var: "10"; }'. ; // Error, missing reqd ~~~~~~~~~ diff --git a/tests/baselines/reference/tsxAttributeResolution11.errors.txt b/tests/baselines/reference/tsxAttributeResolution11.errors.txt index 907b9bce776..c35ec291e51 100644 --- a/tests/baselines/reference/tsxAttributeResolution11.errors.txt +++ b/tests/baselines/reference/tsxAttributeResolution11.errors.txt @@ -1,4 +1,5 @@ -tests/cases/conformance/jsx/file.tsx(11,22): error TS2339: Property 'bar' does not exist on type 'IntrinsicAttributes & { ref?: string; }'. +tests/cases/conformance/jsx/file.tsx(11,22): error TS2322: Type '{ bar: "world"; }' is not assignable to type 'IntrinsicAttributes & { ref?: string; }'. + Weak type 'IntrinsicAttributes & { ref?: string; }' has no properties in common with '{ bar: "world"; }'. ==== tests/cases/conformance/jsx/react.d.ts (0 errors) ==== @@ -27,6 +28,7 @@ tests/cases/conformance/jsx/file.tsx(11,22): error TS2339: Property 'bar' does n // Should be an OK var x = ; ~~~~~~~~~~~ -!!! error TS2339: Property 'bar' does not exist on type 'IntrinsicAttributes & { ref?: string; }'. +!!! error TS2322: Type '{ bar: "world"; }' is not assignable to type 'IntrinsicAttributes & { ref?: string; }'. +!!! error TS2322: Weak type 'IntrinsicAttributes & { ref?: string; }' has no properties in common with '{ bar: "world"; }'. \ No newline at end of file diff --git a/tests/baselines/reference/tsxElementResolution11.errors.txt b/tests/baselines/reference/tsxElementResolution11.errors.txt index 878f5a8b337..54eabef7aed 100644 --- a/tests/baselines/reference/tsxElementResolution11.errors.txt +++ b/tests/baselines/reference/tsxElementResolution11.errors.txt @@ -1,4 +1,5 @@ -tests/cases/conformance/jsx/file.tsx(17,7): error TS2339: Property 'x' does not exist on type '{ q?: number; }'. +tests/cases/conformance/jsx/file.tsx(17,7): error TS2322: Type '{ x: 10; }' is not assignable to type '{ q?: number; }'. + Weak type '{ q?: number; }' has no properties in common with '{ x: 10; }'. ==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== @@ -20,7 +21,8 @@ tests/cases/conformance/jsx/file.tsx(17,7): error TS2339: Property 'x' does not var Obj2: Obj2type; ; // Error ~~~~~~ -!!! error TS2339: Property 'x' does not exist on type '{ q?: number; }'. +!!! error TS2322: Type '{ x: 10; }' is not assignable to type '{ q?: number; }'. +!!! error TS2322: Weak type '{ q?: number; }' has no properties in common with '{ x: 10; }'. interface Obj3type { new(n: string): { x: number; }; diff --git a/tests/baselines/reference/underscoreTest1.errors.txt b/tests/baselines/reference/underscoreTest1.errors.txt deleted file mode 100644 index cdb7991a04e..00000000000 --- a/tests/baselines/reference/underscoreTest1.errors.txt +++ /dev/null @@ -1,907 +0,0 @@ -tests/cases/compiler/underscoreTest1_underscoreTests.ts(252,66): error TS2345: Argument of type '{ variable: string; }' is not assignable to parameter of type 'TemplateSettings'. - Weak type 'TemplateSettings' has no properties in common with '{ variable: string; }'. - - -==== tests/cases/compiler/underscoreTest1_underscoreTests.ts (1 errors) ==== - /// - - declare var $; - declare function alert(x: string): void; - - _.each([1, 2, 3], (num) => alert(num.toString())); - _.each({ one: 1, two: 2, three: 3 }, (value: number, key?: string) => alert(value.toString())); - - _.map([1, 2, 3], (num) => num * 3); - _.map({ one: 1, two: 2, three: 3 }, (value: number, key?: string) => value * 3); - - var sum = _.reduce([1, 2, 3], (memo, num) => memo + num, 0); - - var list = [[0, 1], [2, 3], [4, 5]]; - var flat = _.reduceRight(list, (a, b) => a.concat(b), []); - - var even = _.find([1, 2, 3, 4, 5, 6], (num) => num % 2 == 0); - - var evens = _.filter([1, 2, 3, 4, 5, 6], (num) => num % 2 == 0); - - var listOfPlays = [{ title: "Cymbeline", author: "Shakespeare", year: 1611 }, { title: "The Tempest", author: "Shakespeare", year: 1611 }, { title: "Other", author: "Not Shakespeare", year: 2012 }]; - _.where(listOfPlays, { author: "Shakespeare", year: 1611 }); - - var odds = _.reject([1, 2, 3, 4, 5, 6], (num) => num % 2 == 0); - - _.all([true, 1, null, 'yes'], _.identity); - - _.any([null, 0, 'yes', false]); - - _.contains([1, 2, 3], 3); - - _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); - - var stooges = [{ name: 'moe', age: 40 }, { name: 'larry', age: 50 }, { name: 'curly', age: 60 }]; - _.pluck(stooges, 'name'); - - _.max(stooges, (stooge) => stooge.age); - - var numbers = [10, 5, 100, 2, 1000]; - _.min(numbers); - - _.sortBy([1, 2, 3, 4, 5, 6], (num) => Math.sin(num)); - - - // not sure how this is typechecking at all.. Math.floor(e) is number not string..? - _([1.3, 2.1, 2.4]).groupBy((e: number, i?: number, list?: number[]) => Math.floor(e)); - _.groupBy([1.3, 2.1, 2.4], (num: number) => Math.floor(num)); - _.groupBy(['one', 'two', 'three'], 'length'); - - _.countBy([1, 2, 3, 4, 5], (num) => num % 2 == 0 ? 'even' : 'odd'); - - _.shuffle([1, 2, 3, 4, 5, 6]); - - // (function(){ return _.toArray(arguments).slice(1); })(1, 2, 3, 4); - - _.size({ one: 1, two: 2, three: 3 }); - - /////////////////////////////////////////////////////////////////////////////////////// - - _.first([5, 4, 3, 2, 1]); - _.initial([5, 4, 3, 2, 1]); - _.last([5, 4, 3, 2, 1]); - _.rest([5, 4, 3, 2, 1]); - _.compact([0, 1, false, 2, '', 3]); - - _.flatten([1, 2, 3, 4]); - _.flatten([1, [2]]); - - // typescript doesn't like the elements being different - _.flatten([1, [2], [3, [[4]]]]); - _.flatten([1, [2], [3, [[4]]]], true); - _.without([1, 2, 1, 0, 3, 1, 4], 0, 1); - _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); - _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); - _.difference([1, 2, 3, 4, 5], [5, 2, 10]); - _.uniq([1, 2, 1, 3, 1, 4]); - _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]); - _.object(['moe', 'larry', 'curly'], [30, 40, 50]); - _.object([['moe', 30], ['larry', 40], ['curly', 50]]); - _.indexOf([1, 2, 3], 2); - _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); - _.sortedIndex([10, 20, 30, 40, 50], 35); - _.range(10); - _.range(1, 11); - _.range(0, 30, 5); - _.range(0, 30, 5); - _.range(0); - - /////////////////////////////////////////////////////////////////////////////////////// - - var func = function (greeting) { return greeting + ': ' + this.name }; - // need a second var otherwise typescript thinks func signature is the above func type, - // instead of the newly returned _bind => func type. - var func2 = _.bind(func, { name: 'moe' }, 'hi'); - func2(); - - var buttonView = { - label: 'underscore', - onClick: function () { alert('clicked: ' + this.label); }, - onHover: function () { alert('hovering: ' + this.label); } - }; - _.bindAll(buttonView); - $('#underscore_button').bind('click', buttonView.onClick); - - var fibonacci = _.memoize(function (n) { - return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); - }); - - var log = _.bind((message?: string, ...rest: string[]) => { }, Date); - _.delay(log, 1000, 'logged later'); - - _.defer(function () { alert('deferred'); }); - - var updatePosition = () => alert('updating position...'); - var throttled = _.throttle(updatePosition, 100); - $(null).scroll(throttled); - - var calculateLayout = () => alert('calculating layout...'); - var lazyLayout = _.debounce(calculateLayout, 300); - $(null).resize(lazyLayout); - - var createApplication = () => alert('creating application...'); - var initialize = _.once(createApplication); - initialize(); - initialize(); - - var notes: any[]; - var render = () => alert("rendering..."); - var renderNotes = _.after(notes.length, render); - _.each(notes, (note) => note.asyncSave({ success: renderNotes })); - - var hello = function (name) { return "hello: " + name; }; - hello = _.wrap(hello, (func, arg) => { return "before, " + func(arg) + ", after"; }); - hello("moe"); - - var greet = function (name) { return "hi: " + name; }; - var exclaim = function (statement) { return statement + "!"; }; - var welcome = _.compose(exclaim, greet); - welcome('moe'); - - /////////////////////////////////////////////////////////////////////////////////////// - - _.keys({ one: 1, two: 2, three: 3 }); - _.values({ one: 1, two: 2, three: 3 }); - _.pairs({ one: 1, two: 2, three: 3 }); - _.invert({ Moe: "Moses", Larry: "Louis", Curly: "Jerome" }); - _.functions(_); - _.extend({ name: 'moe' }, { age: 50 }); - _.pick({ name: 'moe', age: 50, userid: 'moe1' }, 'name', 'age'); - _.omit({ name: 'moe', age: 50, userid: 'moe1' }, 'userid'); - - var iceCream = { flavor: "chocolate" }; - _.defaults(iceCream, { flavor: "vanilla", sprinkles: "lots" }); - - _.clone({ name: 'moe' }); - - _.chain([1, 2, 3, 200]) - .filter(function (num) { return num % 2 == 0; }) - .tap(alert) - .map(function (num) { return num * num }) - .value(); - - _.has({ a: 1, b: 2, c: 3 }, "b"); - - var moe = { name: 'moe', luckyNumbers: [13, 27, 34] }; - var clone = { name: 'moe', luckyNumbers: [13, 27, 34] }; - moe == clone; - _.isEqual(moe, clone); - - _.isEmpty([1, 2, 3]); - _.isEmpty({}); - - _.isElement($('body')[0]); - - (function () { return _.isArray(arguments); })(); - _.isArray([1, 2, 3]); - - _.isObject({}); - _.isObject(1); - - - // (() => { return _.isArguments(arguments); })(1, 2, 3); - _.isArguments([1, 2, 3]); - - _.isFunction(alert); - - _.isString("moe"); - - _.isNumber(8.4 * 5); - - _.isFinite(-101); - - _.isFinite(-Infinity); - - _.isBoolean(null); - - _.isDate(new Date()); - - _.isRegExp(/moe/); - - _.isNaN(NaN); - isNaN(undefined); - _.isNaN(undefined); - - _.isNull(null); - _.isNull(undefined); - - _.isUndefined((null).missingVariable); - - /////////////////////////////////////////////////////////////////////////////////////// - - var underscore = _.noConflict(); - - var moe2 = { name: 'moe' }; - moe2 === _.identity(moe); - - var genie; - - _.times(3, function (n) { genie.grantWishNumber(n); }); - - _.random(0, 100); - - _.mixin({ - capitalize: function (string) { - return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase(); - } - }); - (_("fabio")).capitalize(); - - _.uniqueId('contact_'); - - _.escape('Curly, Larry & Moe'); - - var object = { cheese: 'crumpets', stuff: function () { return 'nonsense'; } }; - _.result(object, 'cheese'); - - _.result(object, 'stuff'); - - var compiled = _.template("hello: <%= name %>"); - compiled({ name: 'moe' }); - var list2 = "<% _.each(people, function(name) { %>
  • <%= name %>
  • <% }); %>"; - _.template(list2, { people: ['moe', 'curly', 'larry'] }); - var template = _.template("<%- value %>"); - template({ value: '