diff --git a/_output/java/20230815-mockito-note.md b/_output/java/20230815-mockito-note.md new file mode 100644 index 0000000..32abfbd --- /dev/null +++ b/_output/java/20230815-mockito-note.md @@ -0,0 +1,149 @@ +# Mockito Note + +https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/ + +https://github.com/eugenp/tutorials/tree/master/testing-modules/mockito-simple + +### [difference between doReturn() and when()](https://stackoverflow.com/questions/20353846/mockito-difference-between-doreturn-and-when) + +In the case of mocked objects, it does not matter if it's `when`/`thenReturn` or `doReturn`/`when`. Mocked objects never calls real methods. + +Both approaches behave differently if you use a spied object (annotated with `@Spy`) instead of a mock (annotated with `@Mock`): + +- `when(...) thenReturn(...)` **makes a real method call** just before the specified value will be returned. So if the called method throws an Exception you have to deal with it / mock it etc. Of course you still get your result (what you define in `thenReturn(...)`) +- `doReturn(...) when(...)` **does not call the method at all**. + +### [Difference between @Mock and @InjectMocks](https://stackoverflow.com/questions/16467685/difference-between-mock-and-injectmocks) + +`@Mock` creates a mock. `@InjectMocks` creates an **instance of the class** and injects the mocks that are created with the `@Mock` (or `@Spy`) annotations into this instance. + +Note you must use `@RunWith(MockitoJUnitRunner.class)` or `Mockito.initMocks(this)` to initialize these mocks and inject them (JUnit 4). + +With JUnit 5, you must use `@ExtendWith(MockitoExtension.class)`. + +### mock singleton + +```java +@RunWith(MockitoJUnitRunner.Silent.class) +public class Test { + + @Mock + Singleton singleton; + + @Before + public void setUp() throws Exception { + setUpSingletons(); + } + + @After + public void tearDown() throws Exception { + resetSingletons(); + } + + private void setUpSingletons() throws Exception { + final Field instance = Singleton.class.getDeclaredField("instance"); + instance.setAccessible(true); + instance.set(instance, singleton); + } + + private void resetSingletons() throws Exception { + final Field instance = Singleton.class.getDeclaredField("instance"); + instance.setAccessible(true); + instance.set(instance, null); + } + + @Test + public void test() { + // ... + } +} +``` + +### [Mocking Exception Throwing](https://www.baeldung.com/mockito-exceptions) + +#### Non-Void Return Type + +First, if our method return type is not `void`, we can use `when().thenThrow()`: + +```java +@Test +void givenNonVoidReturnType_whenUsingWhenThen_thenExceptionIsThrown() { + MyDictionary dictMock = mock(MyDictionary.class); + when(dictMock.getMeaning(anyString())).thenThrow(NullPointerException.class); + + assertThrows(NullPointerException.class, () -> dictMock.getMeaning("word")); +} +``` + +#### Void Return Type + +If our method returns `void`, we'll use `doThrow()`: + +```java +@Test +void givenVoidReturnType_whenUsingDoThrow_thenExceptionIsThrown() { + MyDictionary dictMock = mock(MyDictionary.class); + doThrow(IllegalStateException.class).when(dictMock) + .add(anyString(), anyString()); + + assertThrows(IllegalStateException.class, () -> dictMock.add("word", "meaning")); +} +``` + +#### [Checked Exception](https://stackoverflow.com/questions/3762047/throw-checked-exceptions-from-mocks-with-mockito#answer-48261005) + +A workaround is to use a [`willAnswer()`](https://static.javadoc.io/org.mockito/mockito-core/2.13.0/org/mockito/stubbing/OngoingStubbing.html#thenAnswer-org.mockito.stubbing.Answer-) method. + +For example the following works (and doesn't throw a `MockitoException` but actually throws a checked `Exception` as required here) using `BDDMockito`: + +```java +given(someObj.someMethod(stringArg1)).willAnswer( invocation -> { throw new Exception("abc msg"); }); +``` + +The equivalent for plain Mockito would to use the `doAnswer` method + +### [Mocking Static Methods](https://www.baeldung.com/mockito-mock-static-methods) + +https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#static_mocks + +When using the [inline mock maker](https://javadoc.io/static/org.mockito/mockito-core/5.4.0/org/mockito/Mockito.html#0.2), it is possible to mock static method invocations within the current thread and a user-defined scope. This way, Mockito assures that concurrently and sequentially running tests do not interfere. To make sure a static mock remains temporary, it is recommended to define the scope within a try-with-resources construct. In the following example, the `Foo` type's static method would return `foo` unless mocked: + +#### No Argument Static Method + +```java +@Test +void givenStaticMethodWithNoArgs_whenMocked_thenReturnsMockSuccessfully() { + assertThat(StaticUtils.name()).isEqualTo("Baeldung"); + + try (MockedStatic utilities = Mockito.mockStatic(StaticUtils.class)) { + utilities.when(StaticUtils::name).thenReturn("Eugen"); + assertThat(StaticUtils.name()).isEqualTo("Eugen"); + } + + assertThat(StaticUtils.name()).isEqualTo("Baeldung"); +} +``` + +#### Static Method With Arguments + +```java +@Test +void givenStaticMethodWithArgs_whenMocked_thenReturnsMockSuccessfully() { + assertThat(StaticUtils.range(2, 6)).containsExactly(2, 3, 4, 5); + + try (MockedStatic utilities = Mockito.mockStatic(StaticUtils.class)) { + utilities.when(() -> StaticUtils.range(2, 6)) + .thenReturn(Arrays.asList(10, 11, 12)); + + assertThat(StaticUtils.range(2, 6)).containsExactly(10, 11, 12); + } + + assertThat(StaticUtils.range(2, 6)).containsExactly(2, 3, 4, 5); +} +``` + +--- + +欢迎关注公众号【消息中间件】(middleware-mq),更新消息中间件的源码解析和最新动态! + +![](https://scarb-images.oss-cn-hangzhou.aliyuncs.com/img/202205170102971.jpg) diff --git a/_output/other/99991231-ryf-ts-note.md b/_output/other/99991231-ryf-ts-note.md index 1b400ee..19dabd2 100644 --- a/_output/other/99991231-ryf-ts-note.md +++ b/_output/other/99991231-ryf-ts-note.md @@ -160,7 +160,7 @@ y.toFixed() // 不报错 let v1:number = f(); // 不报错 let v2:string = f(); // 不报错 let v3:boolean = f(); // 不报错 - ``` +``` ## 4. 类型系统 @@ -415,6 +415,313 @@ let b:T = a; 凡是可以使用父类型的地方,都可以使用子类型,但是反过来不行。 +## 5. 数组 + +JavaScript 数组在 TypeScript 里面分成两种类型,分别是数组(array)和元组(tuple)。 + +### 5.1 简介 + +TypeScript 的数组所有成员类型必须相同。 + +```ts +let arr:number[] = [1, 2, 3]; +let arr:(number|string)[]; +let arr:any[]; + +// 另一种写法,用 Array 接口 +let arr:Array = [1, 2, 3]; +let arr:Array; +``` + +### 5.2 数组的类型推断 + +```ts +// 推断为 any[] +const arr = []; +// 赋值时会自动更新类型推断 +arr.push(123); +arr // 推断类型为 number[] + +arr.push('abc'); +arr // 推断类型为 (string|number)[] +``` + +类型推断的自动更新只发生初始值为空数组的情况。如果初始值不是空数组,类型推断就不会更新。 + +### 5.3 只读数组,const 断言 + +JavaScript `const`命令声明的数组变量是可以改变成员。TypeScript 允许声明只读数组,方法是在数组类型前面加上`readonly`关键字。 + +TypeScript 将`readonly number[]`与`number[]`视为两种不一样的类型,后者是前者的子类型。(数组是只读数组的子类型) + +```ts +const arr:readonly number[] = [0, 1]; + +arr[1] = 2; // 报错 +arr.push(3); // 报错 +delete arr[0]; // 报错 + +// 另外写法 +const a1:ReadonlyArray = [0, 1]; +const a2:Readonly = [0, 1]; +``` + +### 5.4 多维数组 + +```ts +var multi:number[][] = [[1,2,3], [23,24,25]]; +``` + +## 6. 元组 + +### 6.1 简介 + +TypeScript 特有的数据类型,各个成员的类型可以不同的数组。必须声明每个成员的类型。 + +```ts +// 数组的成员类型写在方括号外面(number[]),元组的成员类型是写在方括号里面([number]) +const s:[string, string, boolean] = ['a', 'b', true]; +// 问号后缀表示该成员是可选的,可选成员必须在必选成员之后 +let a:[number, number?] = [1]; +// 扩展运算符 ... 表示不限成员数量的元组,它可以用在任意位置 +type NamedNums = [ + string, + ...number[] +]; +const a:NamedNums = ['A', 1, 2]; +// 不确定元组成员类型和数量,可以放置任意数量和类型的成员 +type Tuple = [...any[]]; +// 方括号读取成员类型 +type Tuple = [string, number]; +type Age = Tuple[1]; // number +``` + +### 6.2 只读元组 + +```ts +type t = readonly [number, string] +type t = Readonly<[number, string]> // 泛型写法Readonly +``` + +### 6.4 扩展运算符 + +扩展运算符(`...`)将**数组**(注意,不是元组)转换成一个逗号分隔的序列,这时 TypeScript 会认为这个序列的成员数量是不确定的,因为数组的成员数量是不确定的。 + +```ts +const arr = [1, 2, 3]; +console.log(...arr) +``` + +元组使用扩展运算符,成员数量是确定的。 + +## 7. symbol 类型 + +### 7.1 简介 + +Symbol 是 ES2015 新引入的一种原始类型的值。它类似于字符串,但是每一个 Symbol 值都是**独一无二**的,与其他任何值都不相等。 + +```ts +let x:symbol = Symbol(); +let y:symbol = Symbol(); + +x === y // false +``` + +## 8. 函数 + +### 8.1 简介 + +需要在声明函数时,给出参数的类型和返回值的类型。缺乏足够信息,就会推断该参数的类型为`any`。 + +```ts +// 写法一 +const hello = function (txt:string) { + console.log('hello ' + txt); +} + +// 写法二 +const hello: (txt:string) => void = function (txt) { + console.log('hello ' + txt); +}; + +// 用type命令为函数类型定义一个别名,便于指定给其他变量。 +type MyFunc = (txt:string) => void; + +const hello:MyFunc = function (txt) { + console.log('hello ' + txt); +}; +``` + +TypeScript 允许省略参数。 + +### 8.2 Function 类型 + +Function 类型表示函数 + +### 8.3 箭头函数 + +普通函数的一种简化写法。 + +```ts +const repeat = (str:string, times:number):string => str.repeat(times); + +function greet(fn:(a:string) => void):void { + fn('world'); +} +``` + +### 8.4 可选参数 + +```ts +function f(x?:number) { + // ... +} + +f(); // OK +f(10); // OK +``` + +### 8.5 参数默认值 + +```ts +function createPoint(x:number = 0, y:number = 0):[number, number] { + return [x, y]; +} + +createPoint() // [0, 0] +``` + +### 8.6 参数解构 + +可以用类型别名 + +```ts +type ABC = { a:number; b:number; c:number }; + +function sum({ a, b, c }:ABC) { + console.log(a + b + c); +} +``` + +### 8.7 rest 参数 + +表示函数剩余的所有参数,可以试数组,也可以是元组。 + +```ts +// rest 参数为数组 +function joinNumbers(...nums:number[]) { + // ... +} + +// rest 参数为元组 +function f(...args:[boolean, number]) { + // ... +} +``` + +### 8.8 readonly 只读参数 + +```ts +function arraySum(arr:readonly number[]) { + // ... + arr[0] = 0; // 报错 +} +``` + +### 8.9 void 类型 + +表示函数没有返回值 + +```ts +function f():void { + console.log('hello'); +} +``` + +### 8.10 never 类型 + +`never`类型表示肯定不会出现的值。它用在函数的返回值,就表示某个函数肯定不会返回值,即函数不会正常执行结束。 + +#### 抛出错误的函数 + +```ts +function fail(msg:string):never { + throw new Error(msg); +} +``` + +#### 无限执行的函数 + +```ts +const sing = function():never { + while (true) { + console.log('sing'); + } +}; +``` + +### 8.11 局部类型 + +声明其他类型,只在函数内部有效 + +```ts +function hello(txt:string) { + type message = string; + let newTxt:message = 'hello ' + txt; + return newTxt; +} + +const newTxt:message = hello('world'); // 报错 +``` + +### 8.12 高阶函数 + +函数的返回值还是一个函数,那么前一个函数就称为高阶函数(higher-order function)。 + +```ts +(someValue: number) => (multiplier: number) => someValue * multiplier; +``` + +### 8.13 函数重载 + +接受不同类型或不同个数的参数,并且根据参数的不同,会有不同的函数行为。 + +TypeScript 对于“函数重载”的类型声明方法是,逐一定义每一种情况的类型。 + +```ts +// 声明 +function reverse(str:string):string; +function reverse(arr:any[]):any[]; +// 完整类型声明,兼容前面的重载 +function reverse( + stringOrArray:string|any[] +):string|any[] { + if (typeof stringOrArray === 'string') + return stringOrArray.split('').reverse().join(''); + else + return stringOrArray.slice().reverse(); +} +``` + +### 8.14 构造函数 + +使用`new`命令调用。构造函数的类型写法,就是在参数列表前面加上`new`命令。 + +```ts +class Animal { + numLegs:number = 4; +} +// 构造函数 +type AnimalConstructor = new () => Animal; +// 传入一个构造函数 +function create(c:AnimalConstructor):Animal { + return new c(); +} + +const a = create(Animal); +``` + + --- diff --git a/docs/src/java/20230815-mockito-note.md b/docs/src/java/20230815-mockito-note.md new file mode 100644 index 0000000..40dd793 --- /dev/null +++ b/docs/src/java/20230815-mockito-note.md @@ -0,0 +1,157 @@ +--- +title: Mockito Note +author: Scarb +date: 2023-08-15 +--- + +原文地址:[http://hscarb.github.io/java/20230815-mockito-note.html](http://hscarb.github.io/java/20230815-mockito-note.html) + +# Mockito Note + +https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/ + +https://github.com/eugenp/tutorials/tree/master/testing-modules/mockito-simple + +### [difference between doReturn() and when()](https://stackoverflow.com/questions/20353846/mockito-difference-between-doreturn-and-when) + +In the case of mocked objects, it does not matter if it's `when`/`thenReturn` or `doReturn`/`when`. Mocked objects never calls real methods. + +Both approaches behave differently if you use a spied object (annotated with `@Spy`) instead of a mock (annotated with `@Mock`): + +- `when(...) thenReturn(...)` **makes a real method call** just before the specified value will be returned. So if the called method throws an Exception you have to deal with it / mock it etc. Of course you still get your result (what you define in `thenReturn(...)`) +- `doReturn(...) when(...)` **does not call the method at all**. + +### [Difference between @Mock and @InjectMocks](https://stackoverflow.com/questions/16467685/difference-between-mock-and-injectmocks) + +`@Mock` creates a mock. `@InjectMocks` creates an **instance of the class** and injects the mocks that are created with the `@Mock` (or `@Spy`) annotations into this instance. + +Note you must use `@RunWith(MockitoJUnitRunner.class)` or `Mockito.initMocks(this)` to initialize these mocks and inject them (JUnit 4). + +With JUnit 5, you must use `@ExtendWith(MockitoExtension.class)`. + +### mock singleton + +```java +@RunWith(MockitoJUnitRunner.Silent.class) +public class Test { + + @Mock + Singleton singleton; + + @Before + public void setUp() throws Exception { + setUpSingletons(); + } + + @After + public void tearDown() throws Exception { + resetSingletons(); + } + + private void setUpSingletons() throws Exception { + final Field instance = Singleton.class.getDeclaredField("instance"); + instance.setAccessible(true); + instance.set(instance, singleton); + } + + private void resetSingletons() throws Exception { + final Field instance = Singleton.class.getDeclaredField("instance"); + instance.setAccessible(true); + instance.set(instance, null); + } + + @Test + public void test() { + // ... + } +} +``` + +### [Mocking Exception Throwing](https://www.baeldung.com/mockito-exceptions) + +#### Non-Void Return Type + +First, if our method return type is not `void`, we can use `when().thenThrow()`: + +```java +@Test +void givenNonVoidReturnType_whenUsingWhenThen_thenExceptionIsThrown() { + MyDictionary dictMock = mock(MyDictionary.class); + when(dictMock.getMeaning(anyString())).thenThrow(NullPointerException.class); + + assertThrows(NullPointerException.class, () -> dictMock.getMeaning("word")); +} +``` + +#### Void Return Type + +If our method returns `void`, we'll use `doThrow()`: + +```java +@Test +void givenVoidReturnType_whenUsingDoThrow_thenExceptionIsThrown() { + MyDictionary dictMock = mock(MyDictionary.class); + doThrow(IllegalStateException.class).when(dictMock) + .add(anyString(), anyString()); + + assertThrows(IllegalStateException.class, () -> dictMock.add("word", "meaning")); +} +``` + +#### [Checked Exception](https://stackoverflow.com/questions/3762047/throw-checked-exceptions-from-mocks-with-mockito#answer-48261005) + +A workaround is to use a [`willAnswer()`](https://static.javadoc.io/org.mockito/mockito-core/2.13.0/org/mockito/stubbing/OngoingStubbing.html#thenAnswer-org.mockito.stubbing.Answer-) method. + +For example the following works (and doesn't throw a `MockitoException` but actually throws a checked `Exception` as required here) using `BDDMockito`: + +```java +given(someObj.someMethod(stringArg1)).willAnswer( invocation -> { throw new Exception("abc msg"); }); +``` + +The equivalent for plain Mockito would to use the `doAnswer` method + +### [Mocking Static Methods](https://www.baeldung.com/mockito-mock-static-methods) + +https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#static_mocks + +When using the [inline mock maker](https://javadoc.io/static/org.mockito/mockito-core/5.4.0/org/mockito/Mockito.html#0.2), it is possible to mock static method invocations within the current thread and a user-defined scope. This way, Mockito assures that concurrently and sequentially running tests do not interfere. To make sure a static mock remains temporary, it is recommended to define the scope within a try-with-resources construct. In the following example, the `Foo` type's static method would return `foo` unless mocked: + +#### No Argument Static Method + +```java +@Test +void givenStaticMethodWithNoArgs_whenMocked_thenReturnsMockSuccessfully() { + assertThat(StaticUtils.name()).isEqualTo("Baeldung"); + + try (MockedStatic utilities = Mockito.mockStatic(StaticUtils.class)) { + utilities.when(StaticUtils::name).thenReturn("Eugen"); + assertThat(StaticUtils.name()).isEqualTo("Eugen"); + } + + assertThat(StaticUtils.name()).isEqualTo("Baeldung"); +} +``` + +#### Static Method With Arguments + +```java +@Test +void givenStaticMethodWithArgs_whenMocked_thenReturnsMockSuccessfully() { + assertThat(StaticUtils.range(2, 6)).containsExactly(2, 3, 4, 5); + + try (MockedStatic utilities = Mockito.mockStatic(StaticUtils.class)) { + utilities.when(() -> StaticUtils.range(2, 6)) + .thenReturn(Arrays.asList(10, 11, 12)); + + assertThat(StaticUtils.range(2, 6)).containsExactly(10, 11, 12); + } + + assertThat(StaticUtils.range(2, 6)).containsExactly(2, 3, 4, 5); +} +``` + +--- + +欢迎关注公众号【消息中间件】(middleware-mq),更新消息中间件的源码解析和最新动态! + +![](https://scarb-images.oss-cn-hangzhou.aliyuncs.com/img/202205170102971.jpg) diff --git a/docs/src/java/README.md b/docs/src/java/README.md index b696d1b..43f47a3 100644 --- a/docs/src/java/README.md +++ b/docs/src/java/README.md @@ -4,3 +4,5 @@ [廖雪峰 Java 教程 笔记](20230530-lxf-java-note.md) +[Mockito Note](20230815-mockito-note.md) + diff --git a/docs/src/other/99991231-ryf-ts-note.md b/docs/src/other/99991231-ryf-ts-note.md index 1365ab5..b030695 100644 --- a/docs/src/other/99991231-ryf-ts-note.md +++ b/docs/src/other/99991231-ryf-ts-note.md @@ -168,7 +168,7 @@ y.toFixed() // 不报错 let v1:number = f(); // 不报错 let v2:string = f(); // 不报错 let v3:boolean = f(); // 不报错 - ``` +``` ## 4. 类型系统 @@ -423,6 +423,313 @@ let b:T = a; 凡是可以使用父类型的地方,都可以使用子类型,但是反过来不行。 +## 5. 数组 + +JavaScript 数组在 TypeScript 里面分成两种类型,分别是数组(array)和元组(tuple)。 + +### 5.1 简介 + +TypeScript 的数组所有成员类型必须相同。 + +```ts +let arr:number[] = [1, 2, 3]; +let arr:(number|string)[]; +let arr:any[]; + +// 另一种写法,用 Array 接口 +let arr:Array = [1, 2, 3]; +let arr:Array; +``` + +### 5.2 数组的类型推断 + +```ts +// 推断为 any[] +const arr = []; +// 赋值时会自动更新类型推断 +arr.push(123); +arr // 推断类型为 number[] + +arr.push('abc'); +arr // 推断类型为 (string|number)[] +``` + +类型推断的自动更新只发生初始值为空数组的情况。如果初始值不是空数组,类型推断就不会更新。 + +### 5.3 只读数组,const 断言 + +JavaScript `const`命令声明的数组变量是可以改变成员。TypeScript 允许声明只读数组,方法是在数组类型前面加上`readonly`关键字。 + +TypeScript 将`readonly number[]`与`number[]`视为两种不一样的类型,后者是前者的子类型。(数组是只读数组的子类型) + +```ts +const arr:readonly number[] = [0, 1]; + +arr[1] = 2; // 报错 +arr.push(3); // 报错 +delete arr[0]; // 报错 + +// 另外写法 +const a1:ReadonlyArray = [0, 1]; +const a2:Readonly = [0, 1]; +``` + +### 5.4 多维数组 + +```ts +var multi:number[][] = [[1,2,3], [23,24,25]]; +``` + +## 6. 元组 + +### 6.1 简介 + +TypeScript 特有的数据类型,各个成员的类型可以不同的数组。必须声明每个成员的类型。 + +```ts +// 数组的成员类型写在方括号外面(number[]),元组的成员类型是写在方括号里面([number]) +const s:[string, string, boolean] = ['a', 'b', true]; +// 问号后缀表示该成员是可选的,可选成员必须在必选成员之后 +let a:[number, number?] = [1]; +// 扩展运算符 ... 表示不限成员数量的元组,它可以用在任意位置 +type NamedNums = [ + string, + ...number[] +]; +const a:NamedNums = ['A', 1, 2]; +// 不确定元组成员类型和数量,可以放置任意数量和类型的成员 +type Tuple = [...any[]]; +// 方括号读取成员类型 +type Tuple = [string, number]; +type Age = Tuple[1]; // number +``` + +### 6.2 只读元组 + +```ts +type t = readonly [number, string] +type t = Readonly<[number, string]> // 泛型写法Readonly +``` + +### 6.4 扩展运算符 + +扩展运算符(`...`)将**数组**(注意,不是元组)转换成一个逗号分隔的序列,这时 TypeScript 会认为这个序列的成员数量是不确定的,因为数组的成员数量是不确定的。 + +```ts +const arr = [1, 2, 3]; +console.log(...arr) +``` + +元组使用扩展运算符,成员数量是确定的。 + +## 7. symbol 类型 + +### 7.1 简介 + +Symbol 是 ES2015 新引入的一种原始类型的值。它类似于字符串,但是每一个 Symbol 值都是**独一无二**的,与其他任何值都不相等。 + +```ts +let x:symbol = Symbol(); +let y:symbol = Symbol(); + +x === y // false +``` + +## 8. 函数 + +### 8.1 简介 + +需要在声明函数时,给出参数的类型和返回值的类型。缺乏足够信息,就会推断该参数的类型为`any`。 + +```ts +// 写法一 +const hello = function (txt:string) { + console.log('hello ' + txt); +} + +// 写法二 +const hello: (txt:string) => void = function (txt) { + console.log('hello ' + txt); +}; + +// 用type命令为函数类型定义一个别名,便于指定给其他变量。 +type MyFunc = (txt:string) => void; + +const hello:MyFunc = function (txt) { + console.log('hello ' + txt); +}; +``` + +TypeScript 允许省略参数。 + +### 8.2 Function 类型 + +Function 类型表示函数 + +### 8.3 箭头函数 + +普通函数的一种简化写法。 + +```ts +const repeat = (str:string, times:number):string => str.repeat(times); + +function greet(fn:(a:string) => void):void { + fn('world'); +} +``` + +### 8.4 可选参数 + +```ts +function f(x?:number) { + // ... +} + +f(); // OK +f(10); // OK +``` + +### 8.5 参数默认值 + +```ts +function createPoint(x:number = 0, y:number = 0):[number, number] { + return [x, y]; +} + +createPoint() // [0, 0] +``` + +### 8.6 参数解构 + +可以用类型别名 + +```ts +type ABC = { a:number; b:number; c:number }; + +function sum({ a, b, c }:ABC) { + console.log(a + b + c); +} +``` + +### 8.7 rest 参数 + +表示函数剩余的所有参数,可以试数组,也可以是元组。 + +```ts +// rest 参数为数组 +function joinNumbers(...nums:number[]) { + // ... +} + +// rest 参数为元组 +function f(...args:[boolean, number]) { + // ... +} +``` + +### 8.8 readonly 只读参数 + +```ts +function arraySum(arr:readonly number[]) { + // ... + arr[0] = 0; // 报错 +} +``` + +### 8.9 void 类型 + +表示函数没有返回值 + +```ts +function f():void { + console.log('hello'); +} +``` + +### 8.10 never 类型 + +`never`类型表示肯定不会出现的值。它用在函数的返回值,就表示某个函数肯定不会返回值,即函数不会正常执行结束。 + +#### 抛出错误的函数 + +```ts +function fail(msg:string):never { + throw new Error(msg); +} +``` + +#### 无限执行的函数 + +```ts +const sing = function():never { + while (true) { + console.log('sing'); + } +}; +``` + +### 8.11 局部类型 + +声明其他类型,只在函数内部有效 + +```ts +function hello(txt:string) { + type message = string; + let newTxt:message = 'hello ' + txt; + return newTxt; +} + +const newTxt:message = hello('world'); // 报错 +``` + +### 8.12 高阶函数 + +函数的返回值还是一个函数,那么前一个函数就称为高阶函数(higher-order function)。 + +```ts +(someValue: number) => (multiplier: number) => someValue * multiplier; +``` + +### 8.13 函数重载 + +接受不同类型或不同个数的参数,并且根据参数的不同,会有不同的函数行为。 + +TypeScript 对于“函数重载”的类型声明方法是,逐一定义每一种情况的类型。 + +```ts +// 声明 +function reverse(str:string):string; +function reverse(arr:any[]):any[]; +// 完整类型声明,兼容前面的重载 +function reverse( + stringOrArray:string|any[] +):string|any[] { + if (typeof stringOrArray === 'string') + return stringOrArray.split('').reverse().join(''); + else + return stringOrArray.slice().reverse(); +} +``` + +### 8.14 构造函数 + +使用`new`命令调用。构造函数的类型写法,就是在参数列表前面加上`new`命令。 + +```ts +class Animal { + numLegs:number = 4; +} +// 构造函数 +type AnimalConstructor = new () => Animal; +// 传入一个构造函数 +function create(c:AnimalConstructor):Animal { + return new c(); +} + +const a = create(Animal); +``` + + --- diff --git a/other/99991231-ryf-ts-note.md b/other/99991231-ryf-ts-note.md index 9e22cfc..46b2bb5 100644 --- a/other/99991231-ryf-ts-note.md +++ b/other/99991231-ryf-ts-note.md @@ -474,9 +474,250 @@ var multi:number[][] = [[1,2,3], [23,24,25]]; ## 6. 元组 +### 6.1 简介 + TypeScript 特有的数据类型,各个成员的类型可以不同的数组。必须声明每个成员的类型。 ```ts +// 数组的成员类型写在方括号外面(number[]),元组的成员类型是写在方括号里面([number]) const s:[string, string, boolean] = ['a', 'b', true]; +// 问号后缀表示该成员是可选的,可选成员必须在必选成员之后 +let a:[number, number?] = [1]; +// 扩展运算符 ... 表示不限成员数量的元组,它可以用在任意位置 +type NamedNums = [ + string, + ...number[] +]; +const a:NamedNums = ['A', 1, 2]; +// 不确定元组成员类型和数量,可以放置任意数量和类型的成员 +type Tuple = [...any[]]; +// 方括号读取成员类型 +type Tuple = [string, number]; +type Age = Tuple[1]; // number +``` + +### 6.2 只读元组 + +```ts +type t = readonly [number, string] +type t = Readonly<[number, string]> // 泛型写法Readonly +``` + +### 6.4 扩展运算符 + +扩展运算符(`...`)将**数组**(注意,不是元组)转换成一个逗号分隔的序列,这时 TypeScript 会认为这个序列的成员数量是不确定的,因为数组的成员数量是不确定的。 + +```ts +const arr = [1, 2, 3]; +console.log(...arr) +``` + +元组使用扩展运算符,成员数量是确定的。 + +## 7. symbol 类型 + +### 7.1 简介 + +Symbol 是 ES2015 新引入的一种原始类型的值。它类似于字符串,但是每一个 Symbol 值都是**独一无二**的,与其他任何值都不相等。 + +```ts +let x:symbol = Symbol(); +let y:symbol = Symbol(); + +x === y // false +``` + +## 8. 函数 + +### 8.1 简介 + +需要在声明函数时,给出参数的类型和返回值的类型。缺乏足够信息,就会推断该参数的类型为`any`。 + +```ts +// 写法一 +const hello = function (txt:string) { + console.log('hello ' + txt); +} + +// 写法二 +const hello: (txt:string) => void = function (txt) { + console.log('hello ' + txt); +}; + +// 用type命令为函数类型定义一个别名,便于指定给其他变量。 +type MyFunc = (txt:string) => void; + +const hello:MyFunc = function (txt) { + console.log('hello ' + txt); +}; +``` + +TypeScript 允许省略参数。 + +### 8.2 Function 类型 + +Function 类型表示函数 + +### 8.3 箭头函数 + +普通函数的一种简化写法。 + +```ts +const repeat = (str:string, times:number):string => str.repeat(times); + +function greet(fn:(a:string) => void):void { + fn('world'); +} +``` + +### 8.4 可选参数 + +```ts +function f(x?:number) { + // ... +} + +f(); // OK +f(10); // OK +``` + +### 8.5 参数默认值 + +```ts +function createPoint(x:number = 0, y:number = 0):[number, number] { + return [x, y]; +} + +createPoint() // [0, 0] +``` + +### 8.6 参数解构 + +可以用类型别名 + +```ts +type ABC = { a:number; b:number; c:number }; + +function sum({ a, b, c }:ABC) { + console.log(a + b + c); +} +``` + +### 8.7 rest 参数 + +表示函数剩余的所有参数,可以试数组,也可以是元组。 + +```ts +// rest 参数为数组 +function joinNumbers(...nums:number[]) { + // ... +} + +// rest 参数为元组 +function f(...args:[boolean, number]) { + // ... +} +``` + +### 8.8 readonly 只读参数 + +```ts +function arraySum(arr:readonly number[]) { + // ... + arr[0] = 0; // 报错 +} +``` + +### 8.9 void 类型 + +表示函数没有返回值 + +```ts +function f():void { + console.log('hello'); +} +``` + +### 8.10 never 类型 + +`never`类型表示肯定不会出现的值。它用在函数的返回值,就表示某个函数肯定不会返回值,即函数不会正常执行结束。 + +#### 抛出错误的函数 + +```ts +function fail(msg:string):never { + throw new Error(msg); +} +``` + +#### 无限执行的函数 + +```ts +const sing = function():never { + while (true) { + console.log('sing'); + } +}; +``` + +### 8.11 局部类型 + +声明其他类型,只在函数内部有效 + +```ts +function hello(txt:string) { + type message = string; + let newTxt:message = 'hello ' + txt; + return newTxt; +} + +const newTxt:message = hello('world'); // 报错 +``` + +### 8.12 高阶函数 + +函数的返回值还是一个函数,那么前一个函数就称为高阶函数(higher-order function)。 + +```ts +(someValue: number) => (multiplier: number) => someValue * multiplier; +``` + +### 8.13 函数重载 + +接受不同类型或不同个数的参数,并且根据参数的不同,会有不同的函数行为。 + +TypeScript 对于“函数重载”的类型声明方法是,逐一定义每一种情况的类型。 + +```ts +// 声明 +function reverse(str:string):string; +function reverse(arr:any[]):any[]; +// 完整类型声明,兼容前面的重载 +function reverse( + stringOrArray:string|any[] +):string|any[] { + if (typeof stringOrArray === 'string') + return stringOrArray.split('').reverse().join(''); + else + return stringOrArray.slice().reverse(); +} +``` + +### 8.14 构造函数 + +使用`new`命令调用。构造函数的类型写法,就是在参数列表前面加上`new`命令。 + +```ts +class Animal { + numLegs:number = 4; +} +// 构造函数 +type AnimalConstructor = new () => Animal; +// 传入一个构造函数 +function create(c:AnimalConstructor):Animal { + return new c(); +} + +const a = create(Animal); ```