[Question]
  [
## Task
Implement a kind of "some users are typing" system, which can be found in Discord and some other chat clients.
* If 1 user (say, Bubbler) is typing, output `Bubbler is typing...`
* If 2 users (say, Bubbler and user) are typing, output `Bubbler and user are typing...`
* If 3 or more users are typing (say, Bubbler, randomuser1, randomuser2, randomuser3), output `Bubbler and 3 others are typing...`
The input is a list of usernames (list of strings); single string with delimiters (symbols or newlines) is also allowed. The output is a single string. Always respect the order of the input usernames. A username can contain upper/lowercase letters, digits, and spaces. Both usernames and the entire input list are never empty.
Standard [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'") rules apply. The shortest code in bytes wins.
## Test cases
```
["Bubbler"] -> "Bubbler is typing..."
["no one"] -> "no one is typing..."
["HyperNeutrino", "user"] -> "HyperNeutrino and user are typing..."
["emanresu A", "lyxal", "Jo King"] -> "emanresu A and 2 others are typing..."
["pxeger", "null", "null", "null", "null", "null", "null", "null", "null", "null", "null"]
-> "pxeger and 10 others are typing..."
["10", "null", "null", "null", "null", "null", "null", "null", "null", "null", "null"]
-> "10 and 10 others are typing..."
["and", "are"] -> "and and are are typing..."
["is"] -> "is is typing..."
["Bubbler is typing", "is", "are", "and"]
-> "Bubbler is typing and 3 others are typing..."
```
  
[Answer]
# [Whython](https://github.com/pxeger/whython), ~~84~~ 77 bytes
```
f=lambda a,*b:a+f" {'and %s are'%b?'is'%b} typing..."?f(a,f"{len(b)} others")
```
[Attempt This Online!](https://ato.pxeger.com/run?1=m728PKOyJCM_b8GCpaUlaboWN33TbHMSc5NSEhUSdbSSrBK105QUqtUT81IUVIsVEotS1VWT7NUzi4FUrUJJZUFmXrqenp6SfZpGok6aUnVOap5GkmatQn5JRmpRsZIm1NDwgqLMvBKNNA0lp9KkpJzUIiVNTS4MMR0FpYKK1HSCskBWXmlODlAVxHiY2wE)
This is my first answer in Whython, a *horrible* modification of Python [I made](https://www.pxeger.com/2021-09-19-hacking-on-cpython/). Its only new feature so far is `?`, which is a short-circuiting exception [mis-]handling operator.
Here I use it to handle the case where there are more than 2 people typing: I recurse on the function `f` with a newly formatted second argument.
This answer also makes use of the (not Whython-specific) fact that you can `%`-format a string with a tuple of arguments, as long as it's the right number of arguments - and that number can also be `0` or `1` - so both `" is"%()` and `" and %s are"%("second argument",)` work fine.
-7 bytes thanks to @ovs: by trying to format `and %s are` (which requires `b` to be of length 1), then trying to format `is` (which requires `b` to be empty), we can save some bytes by avoiding `len()`.
[Answer]
# [Python 3](https://docs.python.org/3/), 89 bytes
```
lambda a,*b:a+f" {b and'and %s are'%[b[0],'%d others'%len(b)][len(b)>1]or'is'} typing..."
```
[Try it online!](https://tio.run/##K6gsycjPM/6fZhvzPycxNyklUSFRRyvJKlE7TUmhOkkhMS9FHYgVVIsVEotS1VWjk6INYnXUVVMU8ksyUouK1VVzUvM0kjRjoyG0nWFsfpF6ZrF6rUJJZUFmXrqenp7S/4KizLwSjTQNJUclTU0uJJ6OgpITNiEg4QwiXICS/wE "Python 3 – Try It Online")
-2 bytes thanks to dingledooper
[Answer]
# [Haskell](https://www.haskell.org/), 94 bytes
```
g(a:x)=a++f x++" typing..."
f[]=" is"
f[x]=" and "++x++" are"
f l=f[show(length l)++" others"]
```
[Try it online!](https://tio.run/##HY6xbsMwDET3fMVB6GBDjT6ggIcEmdJ06mgYAYPKthBaMiQatb/ekTLdI3ng3UjpaZl3N80hCi4kZG4uCSrnnaQaxyP6ECGjzRrExn2o6GutG9K6x6q1gmyz84MxRh36tmsUXCq0FiT/B6X120fR5j246ds0hv@KrR9kBNflGHJCTKrbJ3IeDSaaf@6o5kV@Jd68GWp8QMhxlnc1tOq8PB5so/qEshP5aNOCU5l4W4kLXAO@c7f89gU "Haskell – Try It Online")
[Answer]
# [Vyxal](https://github.com/Vyxal/Vyxal) `ṡ`, 32 bytes
```
ḣ:[‛λ¬$ḣ[_?L‹‛÷„]‛λ½|_‛is]`Ȯ»...
```
[Try it Online!](https://lyxal.pythonanywhere.com?flags=%E1%B9%A1&code=%E1%B8%A3%3A%5B%E2%80%9B%CE%BB%C2%AC%24%E1%B8%A3%5B_%3FL%E2%80%B9%E2%80%9B%C3%B7%E2%80%9E%5D%E2%80%9B%CE%BB%C2%BD%7C_%E2%80%9Bis%5D%60%C8%AE%C2%BB...&inputs=%5B%22Bubbler%22%2C%22joe%22%2C%22x%22%5D&header=&footer=)
```
ḣ                                # Push the first item (first user) and the rest to the stack
                                 # The first item will remain on the bottom of the stack
 :[                      ]       # If the rest exists (More than one user)
   ‛λ¬$                          # Push 'and' under the rest
       ḣ                         # Push the first item (second user) and rest to the stack
        [       ]                # If the rest exists (≥3 users)
         _                       # Pop the second user
          ?L‹                    # Push the input's length, -1
             ‛÷„                 # Push 'others'
                 ‛λ½             # Push 'are'
                    |            # Otherwise (one user)
                     _‛is        # Pop the resulting empty list and push 'is'
                          `Ȯ»... # Push 'typing'
                                 # (ṡ flag) join stack by spaces)
```
[36 bytes](https://lyxal.pythonanywhere.com?flags=&code=%E1%B8%A3%3A%5B%E2%80%9B%CE%BB%C2%AC%24%E1%B8%A3%5B_%3FL%E2%80%B9%E2%80%9B%C3%B7%E2%80%9E%5D%E2%80%9B%CE%BB%C2%BD%7C_%E2%80%9Bis%5D%60%C8%AE%C2%BB...%60W%E1%B9%84&inputs=%5B%22Bubbler%22%2C%22joe%22%2C%22x%22%5D&header=&footer=) flagless.
[Answer]
# [Pip](https://github.com/dloscutoff/pip), 52 bytes
```
[POgg?["and"#c?[#g"others"]b"are"]"is""typing..."]Js
```
(Or 50 bytes in Pip `-s`, which would use a flag to accomplish the same thing as the `Js` at the end.)
Takes the names as separate command-line arguments. [Try it online!](https://tio.run/##DckxDoAgEATAr5il5wskllhoTyhACZIYIHdQ@PrTaaeXLuKOPWfjEOoFdRqnMtq4EzF8RKAEj8LAeHupWWsNb1lE1hnjk0hsW7Y/ZHKiDw "Pip – Try It Online")
### Explanation
One big list, with the exact contents depending on the number of inputs, joined on spaces:
```
[                   ; List containing:
  PO g              ;  Pop first element of g (the command-line args)
  g ?               ;  Is g still nonempty?
    [               ;   If so (multiple names case), list containing:
      "and"         ;    This string
      # c ?         ;    Is the third cmdline arg nonempty?
        [           ;     If so (more than 2 names case), list containing:
          # g       ;      Number of elements remaining in g
          "others"  ;      and this string
        ]
        b           ;     Otherwise (2 names case), second cmdline arg
      "are"         ;    and this string
    ]
    "is"            ;   Otherwise (single name case), this string
  "typing..."       ;  and this string
]
J s                 ; Join that list (including all sublists) on space
```
[Answer]
# [Vim](https://www.vim.org), ~~92~~ 89 bytes
```
:3,$s/.*/\=line('.')-1.' others'
:1s/\v(\n.+)+/\1
:2s/^/and 
ois typing...<esc>:3s/is/are
V{J
```
[Try it online!](https://tio.run/##BcHBCsIwDADQe76iB6Gb2xKz3Yp68OgHeCrCpkELo5NmK4gfX9/Lpbih3SnhnvxpDlEqi7buGK1Z1rckteBYyefKR2zqhjyD65XuNMangSWoWb@fEF@IeBR9nN2gFJTGJHD7XUu5bNM0SwI@ADNwX7r8Bw "V (vim) – Try It Online")
### Explanation
```
:3,$s/.*/\=line('.')-1.' others'<cr>
```
On every line from line 3 to the end of the buffer (if they exist), replace the contents of the line with the line number minus 1 followed by the string  `others`.
```
:1s/\v(\n.+)+/\1<cr>
```
Beginning at (the end of) line 1, find 1 or more matches of a newline followed by some characters. Replace with the last (newline + characters) match.
```
:2s/^/and <cr>
```
Add `and`  at the beginning of line 2 (if it exists).
```
ois typing...<esc>
```
Open a new line after the cursor (which is always on the last line at the point) and insert `is typing...`.
```
:3s/is/are
```
If that new line was line 3, change `is` to `are` (if it was line 2, leave unchanged).
```
V{J
```
Enter visual line mode, select to the beginning of the buffer, and join lines (space-separated).
[Answer]
# [R](https://www.r-project.org/), ~~113~~ 102 bytes
Or **[R](https://www.r-project.org/)>=4.1, 95 bytes** by replacing the word `function` with `\`.
```
function(s,l=length(s)-1,`?`=paste)s[1]?"if"(l,"and"?"if"(l-1,l?"others",s[2])?"are","is")?"typing..."
```
[Try it online!](https://tio.run/##tVLdSsMwFL73KQ5nNy1kZZ3XtejVUPAFxmDdTLtATEp@YH36epK2m7KqN3oRkkO@v5DP9HXR114dndAqsUwWkqvGnRKbLnO2L/dFW1nHU7vNdyWKGhPJsFJvOA4EkiVqd@LGIrPb9S4tsTIcGQqLdHZdK1STZRn2dXJM8MkfDpIbTNMFLB9gmkFYuELvIlRp0IpfkMM4B9x0LTev3DsjlEYG6O0nhy@3QNkhXAOFvBHi75Uy3Hp4DCqyO1cyHJ41vBDuoniFRbk1DO@flWzPvKEwpKK8lH@2T1EG@RgjX/2UI1/9WwYy/t0/dIaIoRoTL5DiIvgcJRRohNKnz/z7TXeCA7FGHxYtvm9aNL@fD91/AA "R – Try It Online")
It appears that `paste` chains nicely, so we can rename that to `?` and use like string addition (with convenient spaces).
[Answer]
# [C (clang)](http://clang.llvm.org/) with `-m32`, ~~151~~ ~~148~~ 144 bytes
* -3 thanks to ceilingcat
* -4 by changing the base index from 0 to -1
To try a different approach from the other C submission, only the list of strings is needed as input for this answer. To get the length of the list, the function is called recursively and output is printed as the function processes the list.
De-golfed:
```
   g(*s,i) { // type-punning 'char **' as 'int *'
      printf(
        ~i? // is this the first element?
          *s? // (first element) no: end of list?
            i? // (end of list) no: is this the second element?
              "": // (second element) no, don't print if there is only 1 element
              s[1]? // (second element) yes, are there only 2 elements?
                "": // no, don't print second element if there are more than 2
                " and %s": // yes, print second element
            i<2? // (end of list) yes: are there more than 2 elements?
              "": // no
              " and %d others": // yes, print summary
          *s, // (first element) yes: print first element
        *s?
          : // use string if not at end
          i); // otherwise use the list count
      *s?
        g(s+1,i+1): // continue processing list
        printf(" %s typing...", i<2? "is": "are");
   }
   f(s) { g(s,-1); } // initialize list count
```
```
g(*s,i){printf(~i?*s?i?"":s[1]?"":" and %s":i<2?"":" and %d others":*s,*s?:i);*s?g(s+1,i+1):printf(" %s typing...",i?"are":"is");}f(s){g(s,-1);}
```
[Try it online!](https://tio.run/##tVJBT8IwFL7vV7yUmLSjEKc3BhI8GSUcUE@Ew9i60WS0y9rpCJk/3fmKkOj0qKf33tfv@17ar/EgziOVtW1GfcMlOxSlVDalb3Lqm6mcEjIyq2DtKoFIJXBhyEiOr74ACWi7FSXi6ICikWQhloyafsBlP2CjkydBMdh9IVU2HA4JR/eoFOgjDWFhk1LDDqjigwCntidVnFeJgLGxidTD7Y3XS0QqlYDHp@VsuaQ1ujCg8TYq/dWaHWq@eJ7PG8/DbbCLpKIvWiYMDh6AI4Hvm9V64kY4e5DbarPJRUkY/wYrDVqJLnq3L0S5EJXFC2nCgVTmp1TsIlUKU8HMMfJ9HeWuudfwgDfvsotaZOiBBFXl@Z/Vzpbg8r834FdwRy7QzolLl//25iDP38EpkXbSu4JuJ5HLFJuGY3y@DT3sU11SOzEh4Ay23/@MGHHqWxYe26KyhhJynBqvad/jNI8y0w5211ft4PUD "C (clang) – Try It Online")
[Answer]
# JavaScript, 77 bytes
```
a=>a[0]+` ${(l=a.length-1)?`and ${l>1?l+' others':a[1]} are`:'is'} typing...`
```
[Try it online!](https://tio.run/##tU7NqoJQEN73FAe5oOLtkNvCpLu6FPQCIjjVZMY0I@cnkkvP7rVt2K5W8zHf7xmuYPemad2U5YD9MeshW0IxK5NKff1FlIEm5NqdpmmcV8CH4UvLNKckVOJOaGw4hyIt7woMVvOwseFdua5tuNZaV/1e2AqhJqmjY1QEP363IzRBGceLyTPJooRxnPvtWjRb9M40LMG3Crx9FYMXYIPWq9VDR90N6AHWojbDrHFPe8N6yBtk7Inedke70tlHevp/ "JavaScript (Node.js) – Try It Online")
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), 47 bytes
```
ḢɓL,“¥ṃkŒ»ƊḷḊ?“ and ”;;“@k»ʋ;“ is”$ḷ?ṭ⁹“Æʋ@1'ɼ»
```
[Try it online!](https://tio.run/##y0rNyan8///hjkUnJ/voPGqYc2jpw53N2UcnHdp9rOvhju0Pd3TZA0UVEvNSFB41zLW2BnIcsg/tPtUNYilkFgMFVYDq7B/uXPuocSdQ7HDbqW4HQ/WTew7t/v8/WsmpNCkpJ7VIKZYrWsmjsiC1yC@1tKQoMy9fSUdBqbQYKpOam5hXlFpcquAIEs6prEjMATG88hW8M/PSwUoKKlLTgaqBonmlOTlUo0FGGxpQ31iE14GBpFBSWQDyB1A2sxhEJhalgqm8FKVYAA "Jelly – Try It Online")
Full program, as it uses Jelly's smash-printing and nilad dumping.
## How it works
```
ḢɓL,“¥ṃkŒ»ƊḷḊ?“ and ”;;“@k»ʋ;“ is”$ḷ?ṭ⁹“Æʋ@1'ɼ» - Main link. Takes a list of usernames U on the left
Ḣ                                               - Chop off the first username, B, and set U' to be U without its head
 ɓ                                              - Start a new dyadic link f(U', B)
                                   ?            - If:
                                  ḷ             -   U' is non-empty
                           ʋ                    - Then:
             ?                                  -   If:
            Ḋ                                   -     U' has more than one element
          Ɗ                                     -   Then:
  L                                             -     Take the length of U'
    “¥ṃkŒ»                                      -     Compressed string: " others"
   ,                                            -     Pair; [len(U'), " others"]
          ḷ                                     -   Else: Yield B
              “ and ”;                          -   Prepend " and "
                      ;“@k»                     -   Append " are"
                                  $             - Else:
                            ;“ is”              -   Append " is"
                                     ṭ⁹         - Tack all of this to the end of B
                                       “Æʋ@1'ɼ» - Unparseable nilad. Smash print the previous stuff, then print " typing..."
```
[Answer]
## Excel, 100 bytes
```
=A1&IF(COUNTA(A:A)=1," is"," and "&(IF(COUNTA(A:A)=2,A2,COUNTA(A:A)-1&" others"))&" are")&" typing…"
```
[Answer]
# [PHP](https://php.net/), ~~94~~ 91 bytes
```
fn($a)=>"$a[0] ".($a[1]?'and '.($a[2]?count($a)-1 .' others':$a[1]).' are':is).' typing...'
```
[Try it online!](https://tio.run/##tVJPT8IwFD@7T/HSLNlIYDC9gUA0MSFqlPtcSBkdm5lt03YJxPjZ52tBp0LwooelfX2/f12fLGRzOZWF9Dw/H0OT89CnnfGE@DQZpEAiLJM4nQaUryBw1Xk6zUTNjQX2YogCEKZgSgdDB@3gAVUsGJbabs1WlnwdRVHQjNDDMG00jCHxABJyXS@XFVMk7UK/35vAxwGUuiUSB@UCBGctclcfAc62kqkHVhtVckG6QGr91eFbG@ytbN8m/inEXihXTNdwZVWq7YZWdnMr4A5hO0Wwki3Q6Z3v/8cxTblha0yDMryuqj9bP2@303cx4sGJHPHg/zKg8a/@CLBE7LQ8S3Ifwo9QSt1C8dUPH/5gdqwDsvY@XedwYtSc@cVhaC/Fwc2FYjQrQthPMNW4gw68emcsKwQ8a8EXjGdixULXQbsng6Z@HvoGq/lsvrh5vB95b807 "PHP – Try It Online")
Raw first try at it, probably still golfable. It's a pity PHP cannot handle concatenation or nested ternary conditions without brackets..
EDIT: 3 bytes saved with thanks to Dom Hastings and 640KB's suggestions!
[Answer]
# [Ruby](https://www.ruby-lang.org/), ~~79 ...~~ 73 bytes
```
->a,*s{[a,s[0]?[:and,s[1]?[s.size,:others]:s,:are]:"is","typing..."]*" "}
```
[Try it online!](https://tio.run/##tVLNSsQwEL77FMN4W7Kl1VvAFfe0KPgCJYcUs2sgJiVpYKv47HWS0q6yVS96CJlhvj@S8bHph/3NsN5ItgpvtWShLsVtzaV9orKiMhRBvyrGXfesfBA8MC69Ehx1QIZd32p7KIoCxQoB34cW9jVuY9MY5VHAJaw3MPWgA5wIFxlqHTirZuTYLgF3fav8o4qd19YhA4zhk8OXKVB6SGOgpGdC6kVar0KEu6Ri@qM0qbh38EC4WfEEy3JXMD7AomR7VAcKQyo2GvNn9xRllM8xqvKnHFX5bxnI@Hd/QiQijWZeIuVD8CUKbdEEpU9f@Pez3UkOafdGH5Ytvt@0bH69HHr4AA "Ruby – Try It Online")
Thanks ovs for -3 bytes
[Answer]
## Prolog, ~~108~~ 135 bytes (of which 27 are spent on producing a string)
This was fun, although Prolog does not have very much scope for golfery.
My first, unsubmitted, attempt tried to use Prolog's Directed Clause Grammar syntax, but I couldn't get that to be shorter.
IIRC the rules here on CoGoSO correctly, it is permitted to return a string, and not required to print it; so I'm returning in a variable (`O`), as is traditional in Prolog.
```
f([X|R],O):-g(R,P),flatten([X,P,typing],Q),atomics_to_string(Q,' ',O).
g([],is).
g(L,[and,C,are]):-L=[Y],C=Y;C=[N,others],length(L,N).
```
Legend to the one-letter variable names:
```
% X: first name
% R: Rest of the names
% L: Rest of the names, seen from g/2's perspective
% O: Output
% C: Company, i.e. a word list like '[and, Y]'.
% P: intermediate output: nested list of atoms (representing inner words)
% Q: intermediate result: flat list of atoms
```
Usage examples:
```
?- f([jan,piet,klaas,tjoris,korneel], O).
O = "jan and 4 others are typing"
?- f([jan,piet,klaas], O).
O = "jan and 2 others are typing"
?- f([jan,piet], O).
O = "jan and piet are typing"
?- f([jan], O).
O = "jan is typing"
```
Ungolfed:
```
f([X|MoreNames], Out) :-
    % InnerWords like 'is' or '[and, Y, are]'
    innerwords(MoreNames, InnerWords),
    % Flatten `[X, [and, [N others], are], typing]`
    % to `[X, and, N, others, are, typing]`
    flatten([X, InnerWords, typing], AllWords),
    % Turn it into a string. This is not a very Prolog thing to
    % do, but the challeng requests it, so here goes.
    atomics_to_string(AllWords, ' ', Out).
% No more others: produce 'is' for 'X is typing'.
innerwords([], is).
% One or more others
innerwords(MoreNames, [and, Company, are]) :-
    % MoreNames is a list of 1, s
    Company=Y, MoreNames=[Y] ;
    % If we reach here, there are 2+ others.
    % (Or our caller is wrongly asking for additional solutions,
    %  and getting wrong answers as a reward.)
    % [and, [N, others], are]
    Company=[N, others], length(MoreNames, N).
```
[Answer]
# [Julia 1.0](http://julialang.org/), 82 bytes
```
t=" typing..."
>(x)="$x is$t"
x>y="$x and $y are$t"
x>y...=x>"$(length(y)) others"
```
[Try it online!](https://tio.run/##tZLfS8MwEMff91ecoQ8tbGWdb0IL/hiIovjgg1D2kLnbFolpSVNp//p6SaOu1uGLFkpz33zue5deXmopeNJ0nUkZmLYUahfHMZtkYROlLGhAVIFhkyZrXcTVBoIWuEavEpw2GQtCiWpn9mEbRVCYPeqKddtCgxQKQSjQyDd2XYXRBOhxekpyKfkzhjacAptlDNIMWJqxAYZvXIZ3aHhccl31eNQTpRbKSOWkPFn1osaKsrIPkZocwrTfC2Lr2JPUVcoXK6ceomz59LC8fFxenQGbflB9MqrNwDWakNLl7KJeryVqtoIZncVH9CMP/2/OVAGFQg/1wYi5bkvU91gbqlBQeVZXn76DPTcYu2lHM/TAV67ojDWcWwPZNlzaxU0BtwR5sy/IOS38DMduZYM7aoEMVC3ln337Lnpz10EyP9pCMv@n8lTzl9K0bXNI9ymWdy@RI1pUnqKxfp/s6FZYX0rw7lNnfewGuZKnP3f5Dg "Julia 1.0 – Try It Online")
the names are expected as arguments of the function `>`, for example `>("Bubbler")`, `>("a","b","c")`
# [Julia 0.7](http://julialang.org/), ~~79~~ 75 bytes
```
!t=t[(L=end-1;1)]*" $(L<1?:is:"and $(L<2?t[2]:"$L others") are") typing..."
```
[Try it online!](https://tio.run/##tVLLTsMwELz3K7ZWDwlqo6YckAJpxaMSgoI4cECKenCpW4yME9kOar8@rO0UGkLFBSIl8c7Ozqy9fi0FpydV1TWpyYJZyuRyEJ/G4fyIQC@YncWThOuEULl04WhistE8Ib0Z5OaFKU1CoIrh12wLLtdRFJFqlSsQXDLgEhSjS7vWQdgBfByeIlwI@swCG/aBDMYE0jGQdEwaNPZORXDHDI0KqrSnh55RKC6NkA7K4rkHFdNY1W2COyYmPcBXjthNnQ3ux6H7VDJ9ephePk6vEiD9HcsX4wE1VMMOIlVGLsrFQjBF5jDAjdQRcL13MJ2MyBxyyWqSD1qc623B1D0rDTrkaE9K/anbyIGdik3aETQ12BuVuMcSzq2A2G6osIubHG6RVIt9kZzSqB5pW63YsDW2gAKyFOLP/r4LL@46iIcHW4iH/2SPnr9YY9rW2GvuSyzfvchssbmuWTjW75Nt3QqriwW1et9JH7pBzvL45y4/AA "Julia 0.7 – Try It Online")
[Answer]
# [Perl 5](https://www.perl.org/) + `-pl`, 61 bytes
Thanks to [@Xcali](https://codegolf.stackexchange.com/users/72767/xcali) for -2!
```
s;$; @{[!(@_=<>)?is:'and',$#_?@_.' others':@_,are]} typing...
```
[Try it online!](https://dom111.github.io/code-sandbox/#eyJsYW5nIjoid2VicGVybC01LjI4LjEiLCJjb2RlIjoiczskOyBAe1shKEBfPTw+KT9pczonYW5kJywkI18/QF8uJyBvdGhlcnMnOkBfLGFyZV19IHR5cGluZy4uLiIsImFyZ3MiOiItcGwiLCJpbnB1dCI6IkJ1YmJsZXJcbnVzZXIxXG51c2VyMiJ9)
## Explanation
The first name is implicitly stored in `$_` (via `-p`) so it's easy to just add to it a string consisting of a leading space and an in-line list `@{[...]}`, finishing with  `typing...` as that's always needed no matter what. The in-line list will be implicitly joined by `$"` (space), which allows use of some barewords, saving bytes for the quotes. The rest of the input (`<>`) is slurped into `@_` which, if it's non-empty, results in a list consisting of `'and'`, and if `$#_` is truthy (`$#_` is the last array index of `@_`, which will be `0` if there is only one entry), we use `@_` in a scalar context (which is the number of elements i n`@_`) concatenated with `' others'`, but if `@_` only contains one entry, add it as is. If `@_` is empty, we just add the bareword `is` to the in-line list.
[Answer]
# [Vyxal](https://github.com/Vyxal/Vyxal) `ṡ`, ~~42~~ 41 bytes
```
ḢḢ[₌hL‹` ÷„`+"]` λ¬ `j`is λ½`⌈?L‹ḃi`Ȯ»...
```
[Try it Online!](https://lyxal.pythonanywhere.com?flags=%E1%B9%A1&code=%E1%B8%A2%E1%B8%A2%5B%E2%82%8ChL%E2%80%B9%60%20%C3%B7%E2%80%9E%60%2B%22%5D%60%20%CE%BB%C2%AC%20%60j%60is%20%CE%BB%C2%BD%60%E2%8C%88%3FL%E2%80%B9%E1%B8%83i%60%C8%AE%C2%BB...&inputs=%5B%22Joe%22%2C%20%22Mama%22%2C%20%27lol%27%5D&header=&footer=)
Lovely dictionary compression. [44 bytes flagless](https://lyxal.pythonanywhere.com?flags=&code=%E1%B8%A2%E1%B8%A2%5B%E2%82%8ChL%E2%80%B9%60%20%C3%B7%E2%80%9E%60%2B%22%5D%60%20%CE%BB%C2%AC%20%60j%60is%20%CE%BB%C2%BD%60%E2%8C%88%3FL%E2%80%B9%E1%B8%83i%60%C8%AE%C2%BB...%60W%E1%B9%84&inputs=%5B%22Joe%22%2C%20%22Mama%22%2C%20%27lol%27%5D&header=&footer=)
## Explained
```
ḢḢ[₌hL‹` ÷„`+"]` λ¬ `j`is λ½`⌈?L‹ḃi`Ȯ»...
ḢḢ                                         # If the length of the input is > 2:
  [₌hL‹                                    #     Push the head of the input and the length of the input - 1
       ` ÷„`+                              #     and append the string " others" to that
             "                             #     and wrap both in a list
              ]                            # endif
               ` λ¬ `j                     # Join the top of the stack on " and "
                      `is λ½`⌈             # Push the list ["is", "are"]
                              ?L‹          # And push the lenght of the input - 1
                                 ḃi        # boolify it to make it 0 or 1 (this is basically just checking if the list length is 1) and index into the list
                                   `Ȯ»...  # Push "typing..." to the stack
                                           # The -ṡ flag joins the stack on spaces. Without it, you'd need `WṄ for +3 bytes.
```
[Answer]
# [05AB1E](https://github.com/Adriandmen/05AB1E/wiki/Commands), 42 [bytes](https://github.com/Adriandmen/05AB1E/wiki/Codepage)
```
ćs©gĀi'€ƒ®ćsgĀi\Ig<'ˆ†]…is€™#Ig≠è“ÜÔ...“ðý
```
[Try it online](https://tio.run/##yy9OTMpM/f//SHvxoZXpRxoy1R81rTk26dA6oACIG@OZbqN@uu1Rw4LYRw3LMouBso9aFil7pj/qXHB4xaOGOYfnHJ6ip6cHYm04vPf//2glp9KkpJzUIiUdpdJiMFWSWlwCpJJyEpViAQ) or [verify all test cases](https://tio.run/##yy9OTMpM/V9Waa@k8KhtkoKSfaXS/yPtxYdWph9pyFR/1LTm2KRD64ACIG5MZbqN@um2Rw0LYh81LMssBso@almkXJn@qHPB4RWPGuYcnnN4ip6eHoi14fDe/0p6YTr/o6OVnEqTknJSi5RidaKV8vIV8vNSwUyPyoLUIr/U0pKizLx8JR2l0mKomtTcxLyi1OJSBUegaE5lRWIOkPbKV/DOzEsHKyioSE0HqtVRyivNyaGUAhloaEBFwxLzUoDcxCKILzOLwRQ0DBQyixVKKgtAHtEBSUHU6YD1ICmDhYaOUklqcQmQSspJVIqNBQA).
**Explanation:**
```
ć                       # Extract head of the (implicit) input-list; pop and push
                        # remainder-list and first item separately
 s                      # Swap so the remainder-list is at the top
  ©                     # Store it in variable `®` (without popping)
   gĀi                  # Pop and if there are any strings left (2+ inputs):
      '€ƒ              '#  Push dictionary string "and"
         ®              #  Push list `®`
          ćs            #  Extract head and swap again
            gĀi         #  Pop and if there are any strings left (3+ inputs):
               \        #   Discard the head we've pushed
                Ig<     #   Push the input-length - 1
                   'ˆ† '#   Push dictionary string "others"
     ]                  # Close both if-statements
      …is€™             # Push dictionary string "is are"
           #            # Split it on spaces: ["is","are"]
            Ig          # Push the input-length
              ≠         # Check that it's NOT 1 (0 if 1; 1 otherwise)
               è        # Use that to index into the pair
      “ÜÔ...“           # Push dictionary string "typing..."
ðý                      # Join the entire stack with space delimiter
                        # (after which the result is output implicitly)
```
[See this 05AB1E tip of mine (section *How to use the dictionary?*)](https://codegolf.stackexchange.com/a/166851/52210) to understand why `'€ƒ` is `"and"`; `'ˆ†` is `"others"`; `…is€™` is `"is are"`; and `“ÜÔ...“` is `"typing..."`.
[Answer]
# [Retina 0.8.2](https://github.com/m-ender/retina/wiki/The-Language/a950ad7d925ec9316e3e2fb2cf5d49fd15d23e3d), 63 bytes
```
^.*$
$& is
(¶.*){2,}
¶$#1 others
¶(.*)
 and $1 are
$
 typing...
```
[Try it online!](https://tio.run/##nY9NCsIwEIX3c4oBo9QyBOsNdCUKbtyLKQ4aiEnJD7SI1@oBerGaQi@gmwfz3jx4n@eorRqXxeVG41WWAsQKdYBi6GW5fm/pA0MvFhW6@GQf8lFkH1DZO4oKlWcQgLFrtH1IKcdxn@rasAfr0FmGQ9ewP3OKXltHKeSEX8p6Dgl3ZLpWGTo6POU6NC0/2JNNxvwkUG3@KGUCmuZn2Hlz5p5JSIcpo/zzBQ "Retina 0.8.2 – Try It Online") Takes newline-delimited input but test suite splits on commas for convenience. Explanation:
```
^.*$
$& is
```
Just one person is typing.
```
(¶.*){2,}
¶$#1 others
```
If there are at least two others then replace the list with a single element giving their count.
```
¶(.*)
 and $1 are
```
More than one person is typing.
```
$
 typing...
```
Complete the sentence.
[Answer]
# [Charcoal](https://github.com/somebody1234/Charcoal), 48 bytes
```
Ｓ ＷＳ⊞υι¿υ«and ¿⊖Ｌυ⁺Ｌυ others⊟υ are»is¦ typing...
```
[Try it online!](https://tio.run/##XY7LCsIwFETXzVdcskpB@wNdCW58LAp@QWivTSBNSh5qEb89JvVV3F1mztyZVnDbGq5ibKzUnu30GPzJp7tnZVmTl0qBpvsqpEL4Q6AJTrCwApkIeQYWSriT4p3jupujRXa22FocUHvs2BF171MuP5jRRgX3U1dAwXiB1tG8okDl8AOaMcfqbwdwi7njQRYUlY4u5vtpTHOrqkpijDhwbdEF2BA13bgiewOH5JO4vqgn "Charcoal – Try It Online") Link is to verbose version of code. Takes input as a list of newline-terminated strings, which for some reason is golfier than taking input as a JSON list. Explanation:
```
Ｓ 
```
Output the first name and a space.
```
ＷＳ⊞υι
```
Read in any other names.
```
¿υ«
```
If there were any, then:
```
and 
```
Output `and`  (with a trailing space).
```
¿⊖Ｌυ
```
If there was more than one other, then...
```
⁺Ｌυ others
```
... concatenate the count to the string  `others` (with a leading space) and output that, otherwise...
```
⊟υ
```
... output the last (and only other) name.
```
 are
```
Output  `are` (with a leading space).
```
»is
```
Otherwise, output `is`.
```
 typing...
```
Output  `typing...` (with a leading space).
[Answer]
# [C (clang)](http://clang.llvm.org/) `-m32`, ~~109~~ 107 bytes
*-2 thanks to ErikF!*
```
t(*n,l){printf(--l?l-1?"%s and %d others are%s":"%s and %s are%s":"%s is%3$s",*n,l-1?l:n[1]," typing...");}
```
[Try it online!](https://tio.run/##vVNdb4IwFH3fr7hpRgJanIpf6BazPS1bsj9geECt2KQWQkumM/71sZaCmUp4WsbLoT3nnlN6Lyt3xUIe5bm0Wxwz55iklMuN7bpsztzeHFkCQr4Gaw2x3JJUrVJiCTQ9Exc7VFjevUBYe6lqNuWLXoARyENCedTpdJAzO@UqAXYh5bZzvAP1rLZhCi1JhOwtAniCI6CXbLlkJEVwml1J@pWExxBzUqPwKsXrISHpB8mk@qYYYUCZqLUcVAVkF/KUiAyetZod9iHTL28xvKvj11QOq8pkTyLlrcQ8Y@zP8DZxVCX2uv@QNq7SVKu1TLW6RjWpVFTUsP5VT9WQlPOgHVVJ6YtNyqVB4SBKh2JCcAF9A56BgYGhgZGBsYGJAV/7FsZ6@hjhkdyWvsWufgT9IvHGxMBDubT1QVoO/s32G1nvhq1LGDR6DBvZ0S1bFzFuNJk0sv41WwScMFDTnk2c2lTdXncGFB7BV9BuOyBt0zAa4PMl00BZJ5kUNlK//90p/15tWBiJ3P3M3Z3X/wE "C (clang) – Try It Online") Takes input as an array of `char*` and its length.
# [C (clang)](http://clang.llvm.org/), ~~115~~ 108 bytes
*-7 thanks to ErikF!*
```
t(**n,l){printf(--l?l-1?"%s and %d others are%s":"%s and %s are%s":"%s is%3$s",*n,l-1?l:n[1]," typing...");}
```
[Try it online!](https://tio.run/##vVNdb4IwFH3fr7hpRgJanIpf6BazPS1bsj9gfEAt2KQWQkumM/71sZaCmUp4WsbLoT3nnlN6L2t3zQIe5bm0Wy2OmXNMUsplaLsumzO3N0eWgIBvwNpALLckVauUWAJNz8TFDhWWdy8Q1l6qmk35orfECOQhoTzqdDrImZ1ylQC7gHLbOd6BetbbIIWWJEL2Fkt4giOgl2y1YiRFcJpdSfqVhMcQc1Kj8CrF6yEh6QfJpPqmGGFAmai1HFQFZBfwlIgMnrWaHfYB0y9vMbyr49dUDqvKZE8i5a3EPGPsz/A2cVQl9rr/kDau0lSrtUy1ukY1qVRU1LD@VU/VkJTzoB1VSemLTcqlQeEgSodiQnABfQOegYGBoYGRgbGBiQFf@xbGevoY4ZHclr7Frn4E/SJxaGLgoVza@iAtB/9m@42sd8PWJQwaPYaN7OiWrYsYN5pMGln/mi0CThioaU8YpzZVt9edAYVH8BW02w5I2zSMLvH5kulSWSeZFDZSv//dKf9ehyyIRO5@/gA "C (clang) – Try It Online") Takes input as an array of `char*` and its length.
[Answer]
# [Zsh](https://www.zsh.org), 67 bytes
```
x=(is "and $2 are")
echo $1 ${x[#]-and $[~-#] others are} typing...
```
[Attempt This Online!](https://ato.pxeger.com/run?1=m724qjhjwYKlpSVpuhY3nStsNTKLFZQS81IUVIwUEotSlTS5UpMz8hVUDBVUqiuilWN1wXLRdbrKsQr5JRmpRcUgZbUKJZUFmXnpenp6EKOgJm6NVnIqTUrKSS1S0lFQKqhITQeyYqGSAA)
Looks up the correct format string into the array `$x` (one of `is`, `and $2 are`, or an unset variable), defaulting to `and $[~-#] others are` (where `$[~-#]` is `number of arguments - 1`), and prints that with the first input `$1` and the string `typing...`.
---
## [Zsh](https://www.zsh.org), 79 bytes
```
T=\ typing...
1()<<<$1\ is$T
2()<<<"$1 and $2 are$T"
$# $@||2 $1 $[~-#]\ others
```
[Attempt This Online!](https://ato.pxeger.com/run?1=m724qjhjwYKlpSVpuhY3_UNsYxRKKgsy89L19PS4DDU0bWxsVAxjFDKLVUK4jMBcJRVDhcS8FAUVI4XEolSVECUuFWUFFYeaGiMFoIxKdJ2ucmyMQn5JRmpRMcRYqOlbo5WcSpOSclKLlHQUlAoqUtOBrFioJAA)
* Defines two functions called `1` and `2` which print formatted messages for singular and plural, respectively
* Then it calls the function with the name `$#` (the number of arguments), so that if 1 or 2 people are typing, the correct message is printed
* If there are more than 2 arguments, the function call will fail, triggering the `||` branch
	+ This calls `2` with the first argument and the string `$[~-#] others`
		- (It has to be `~-#`, because `#-1` doesn't work, although I don't really understand why)
[Answer]
## Batch, 170 bytes
```
@if "%2"=="" echo %~1 is typing...&exit/b
@set s=%~1
@set t=%~2
@set n=2
:l
@if not "%3"=="" set t=%n% others&set/an+=1&shift&goto l
@echo %s% and %t% are typing...
```
Takes input as command-line parameters. Explanation:
```
@if "%2"=="" echo %~1 is typing...&exit/b
```
Handle the case of there only being one user.
```
@set s=%~1
@set t=%~2
@set n=2
```
Assume there are two users.
```
:l
@if not "%3"=="" set t=%n% others&set/an+=1&shift&goto l
```
While more users are found, update the number of others and increment the total number of users.
```
@echo %s% and %t% are typing...
```
Output the users or count as appropriate.
[Answer]
# [Python3](https://docs.python.org/3/), 95 bytes:
```
lambda d:f'{d[0]} {"and "+[d[1],f"{l-1} others"][l>2]+" are"if(l:=len(d))>1else"is"} typing...'
```
This solution requires no pre-formatting of the input list (i.e no unpacking).
[Answer]
# [Rust](https://www.rust-lang.org/), ~~185~~ ~~183~~ ~~162~~ 136 bytes
```
|v:&[&str]|[v[0],&match v.len(){1=>"is".into(),2=>format!("and {} are",v[1]),l=>format!("and {} others are",l-1)},"typing..."].join(" ")
```
[Try it online!](https://tio.run/##tZRbT8MgFMff9ynOeGiKQbLON5ct0SejiV9gWZZO2YZhMIE2u372eehuKmv0QUkaCud3LvR/qC2c3401zHKpUwrrBuBQwsOiu9uUt0k/cd4ONv2y3xqwZJb7lymUXAmE11m3R6QjXGpvUsra3d7YWESaKcn1K6y3kFtBWNnPBpSp2Gr8VFi3h9R1RreM@OVc6gnnnAz4m8GSCBC661RVnUorxYuHbpiaabUZRrUi98VopIQllH0zaANGi3j/YTkX9lkU3kptCANSuEvuYpZrK1wBd4FRy0WuwsujgSesN@bnCzHBOIjoQqk/m6M8Wev/c6BawRhkimwof7R30ACkg72cwRvBQ4wwYUTKaKdxktRFesZhQleccx0UrTV/ERZCxwVlQ7Nd5s8KV3D7U3dedthLXMFZ60cakV@SAaseBGohPHXdwaPvVkW7qcl7FAHvJqxA6upycemFTSlfyXnqDovjvyGM3OGn9EPx3kwXabLiLe7NEB2RYnC14hnd39htY7v7AA "Rust – Try It Online")
Ungolfed:
```
|v: &[&str]| {
        [
            v[0],
            &match v.len() {
                1 => "is".into(),
                2 => format!("and {} are", v[1]),
                l => format!("and {} others are", l - 1),
            },
            "typing...",
        ]
        .join(" ")
    }
```
Log:
* -2 for excluding the closure name
* -21 for `v:&[&str]`, implicit return type, wildcard with binding, `s` removal, brackets. Thanks @AnttiP!
* -26 for removing redundant `"typing..."` occurrences and one `format!` use (by @Ezhik)
[Answer]
# [BQN](https://mlochbaum.github.io/BQN/), 77 bytes
```
⊑∾" typing..."∾˜·(0<≠)◶⟨" is"⋄" and "∾" are"∾˜(1<≠)◶⟨⊑⋄" others"∾˜•fmt∘≠⟩⟩1⊸↓
```
Anonymous tacit function that takes a list of strings and returns a string. [Run it online!](https://mlochbaum.github.io/BQN/try.html#code=RiDihpAg4oqR4oi+IiB0eXBpbmcuLi4i4oi+y5zCtygwPOKJoCnil7bin6giIGlzIuKLhCIgYW5kICLiiL4iIGFyZSLiiL7LnCgxPOKJoCnil7bin6jiipHii4QiIG90aGVycyLiiL7LnOKAomZtdOKImOKJoOKfqeKfqTHiirjihpMKCkbCqCDin6gg4p+oICJCdWJibGVyIiDii4QgInVzZXIiIOKLhCAibHl4YWwiIOKLhCAiTmVpbCIg4p+pCiAgIOKLhCDin6ggIkJ1YmJsZXIiIOKLhCAidXNlciIg4p+pCiAgIOKLhCDin6ggIkJ1YmJsZXIiIOKfqSDin6kK)
### Explanation
```
(0<≠)◶⟨" is"⋄...⟩1⊸↓
                 1⊸↓  Drop the first element of the argument list
(   )◶                Choose, based on the result of this function:
   ≠                     Length of the remaining list
 0<                      is greater than 0? (1 if so, 0 if not)
      ⟨         ⟩      one of these functions:
       " is"             Return that string
            ⋄         or...
" and "∾" are"∾˜(1<≠)◶⟨⊑⋄...⟩
                (   )◶         Choose, based on the result of this function:
                   ≠              Length of the all-but-the first list
                 1<               is greater than 1?
                       ⟨     ⟩  one of these functions:
                        ⊑         First element of the all-but-the-first list
                         ⋄     or... (see below)
        " are"∾˜               Append that string to the result
" and "∾                       Prepend that string to the result
" others"∾˜•fmt∘≠
                ≠  Length of the all-but-the-first list
           •fmt∘   Format as string
" others"∾˜        Append that string to the result
⊑∾" typing..."∾˜·...
                  ...  Calculate all of the above
                 ·     and then
   " typing..."∾˜      Append that string to the result
⊑∾                     Prepend the first element of the argument list
```
[Answer]
# JavaScript, ~~85~~ 82 bytes
```
a=>(b=a.length,a[0]+(b<2?" is":` and ${b<3?a[1]:b-1+" others"} are`)+" typing...")
```
[Try it online!](https://tio.run/##tU7LSsNQEN37FcPgIqHtpam70rToShT8gRDo3HaaRq4z4T6kQfz2NN1K3OlqDnOe7/RJ4eDbLi5EjzycyoHKbWZLMo6liec5Vct6ltnNaofQBlzvgeQI919287CjqqjXdlHMEDSe2Qf8BvK8z8dH7LtWGmMM5sNBJahj47TJTlmFT8laxx7rPL/7yYmCCk9Sz33H/o1T9K0ozgFT@CWEP0g8hwSPN5nrL@Ru4EXhdRw1aeku3Ixpo0qSc392p6qK5X/UDFc "JavaScript (Node.js) – Try It Online")
[Answer]
# Dart, 101 Bytes
```
f(a)=>a[0]+(a.length>1?" and ${a.length>2?"${a.length-1} others":"${a[1]}"} are" : " is")+" typing.";
```
[Try it online](https://dartpad.dev/?id=3332dd3638698d3ba294eb7da60bd6f1&null_safety=true)
[Answer]
# [Python 2](https://docs.python.org/2/), 102 bytes
```
i=input()
l=len(i)
print(i[0]+" and "+[`l-1`+" others",i[-1]][l<3]+" are",i[0]+" is")[l<2],"typing..."
```
[Try it online!](https://tio.run/##XY1BCsMgFET3niL8jdoYadIu60lESJpI80FUjIXm9DZmVboZZh4zTNzzGvxQ5rBYRSktqNDHd2acOOWsZ8hJTOgzQ301LTSTXxpo9ei6fjxiyKtNGwjUXW@Mdo/bWUq2onOAG/CDD0ZA3iP6l5QSynFF7MfOrB7zy71omMCQqgKeP07A/JcELGC@ "Python 2 – Try It Online")
Simple nested list slices but takes advantage of no brackets required for printing in Python 2 and also the use of back ticks for the string conversion.
[Answer]
# [jq](https://stedolan.github.io/jq/), ~~99~~ 99+1 (-r flag penalty) = 100 bytes
```
(length-1)as$l|.[0]as$n|["is","and \(.[1]) are"]|"\($n) \(.[$l]//"and \($l) others are") typing..."
```
[Try it online!](https://tio.run/##LY1BCsMgEEWvMgwuHEhMc4Vew7gwRBLLMG3VLgre3TaS1f/89@A/3q1pDrKXY5zJZ8XV2Jv7F6kWY8YBvWywaGNnR@BTQFdx0Uqoj4rdNF2KYoJnOULK3SMo31eU3RiDrVm8f9aVQ4KYL4AD9AfAUz9DNnRtTD8 "jq – Try It Online")
I'm pretty sure there's room to golf this more, but not tonight. :)
1. Stash the length of the input list in `$l`. stash the first element in `$n
`(length-1)as$l|.[0]as$n`
2. Generate a new list consisting of two elements, `is` and `is 2nd-input-list-entry are`
`|["is","and \(.[1]) are"]`
3. Print the first input list name, then index the list from step 2 by the number of entries in the input minus 1. The `//` code is called if the index doesn't exist. In that case the alternate text `and length-of-input-minus-1 are` is used. The `typing...` string is appended regardless of what other choices were made.
`|"\($n) \(.[$l]//"and \($l) others are") typing..."`
]